NumPy¶

NumPy’s main object is an homogeneous multidimensional array:

  • it is a table of elements (usually numbers), all of the same type, indexed by a tuple of positive integers,
  • dimensions are called axes,
  • the number of axes is called the rank.

Concepts, notation, examples¶

Numpy’s array class is called ndarray. It is also known by the alias array.

Warning : numpy.array is not the same as the Standard Python Library class array.array.

It is very common to alias numpy into np when importing.

In [1]:
import numpy as np
print(np)
<module 'numpy' from '/root/.cache/pypoetry/virtualenvs/pyplot-doc-VOfsvtlq-py3.11/lib/python3.11/site-packages/numpy/__init__.py'>

The coordinates of a point in 3D space is an array of rank 1, because it has one axis. That axis has a length of 3.

In [2]:
point = np.array([1, 2, 1])
print(point)

print()
print(type(point))
print(point.ndim, point.shape) # the rank, and size of each axe (dimension)
print(point.size, point.dtype) # total number of elements, and kind of elements.

print()
print(point[0], point[1], point[2])
[1 2 1]

<class 'numpy.ndarray'>
1 (3,)
3 int64

1 2 1

The array below has rank 2 (it is 2-dimensional):

  • the first axis (dimension) has a length of 2,
  • the second axis has a length of 3.
In [3]:
point = np.array([[ 1., 0., 0.],
                  [ 0., 1., 2.]])
print(point)

print()
print(type(point))
print(point.ndim, point.shape) # the rank, and size of each axe (dimension)
print(point.size, point.dtype) # total number of elements, and kind of elements.

print()
print(point[0, 0], point[0, 1], point[0, 2])
print(point[1, 0], point[1, 1], point[1, 2])
[[1. 0. 0.]
 [0. 1. 2.]]

<class 'numpy.ndarray'>
2 (2, 3)
6 float64

1.0 0.0 0.0
0.0 1.0 2.0

Few other ways to create NumPy arrays:

In [4]:
np.zeros((3,4)) # create a matrix (3,4) and init with zeroes
Out[4]:
array([[0., 0., 0., 0.],
       [0., 0., 0., 0.],
       [0., 0., 0., 0.]])
In [5]:
np.ones((2,3,4), dtype=np.int16) # create a matrix (2,3,4) and init with ones
Out[5]:
array([[[1, 1, 1, 1],
        [1, 1, 1, 1],
        [1, 1, 1, 1]],

       [[1, 1, 1, 1],
        [1, 1, 1, 1],
        [1, 1, 1, 1]]], dtype=int16)
In [6]:
np.arange( 10, 30, 5 ) # create a 1D array and init with a uniform
                       # sequence of numbers (10…30, every 5)
Out[6]:
array([10, 15, 20, 25])
In [7]:
np.linspace( 0, 2, 9 ) # create a 1D array and init with a linear
                       # sequence of 9 numbers (0…2)
Out[7]:
array([0.  , 0.25, 0.5 , 0.75, 1.  , 1.25, 1.5 , 1.75, 2.  ])

Operations¶

Arithmetic operators on arrays apply elementwise. A new array is created and filled with the result.

In [8]:
a = np.array( [20, 30, 40, 50] )
b = np.arange( 4 )
print(a)
print(b)
[20 30 40 50]
[0 1 2 3]
In [9]:
a-b
Out[9]:
array([20, 29, 38, 47])
In [10]:
b**2
Out[10]:
array([0, 1, 4, 9])
In [11]:
10*np.sin(a)
Out[11]:
array([ 9.12945251, -9.88031624,  7.4511316 , -2.62374854])
In [12]:
a<35
Out[12]:
array([ True,  True, False, False])

Let's try with 2D operations.

In [13]:
a = np.array( [[1,1], [0,1]] )
b = np.array( [[2,0], [3,4]] )
print(a)
print(b)
[[1 1]
 [0 1]]
[[2 0]
 [3 4]]
In [14]:
a*b # elementwise product
Out[14]:
array([[2, 0],
       [0, 4]])
In [15]:
a.dot(b)    # matrix product
Out[15]:
array([[5, 4],
       [3, 4]])
In [16]:
np.dot(a,b) # another matrix product
Out[16]:
array([[5, 4],
       [3, 4]])
In [17]:
print(a.sum())
print(a.min())
print(a.max())
3
0
1
In [18]:
np.exp(b)
Out[18]:
array([[ 7.3890561 ,  1.        ],
       [20.08553692, 54.59815003]])
In [19]:
np.sqrt(b)
Out[19]:
array([[1.41421356, 0.        ],
       [1.73205081, 2.        ]])
In [20]:
c = np.array( [[1, 1, 2], [0, 1, 2]] )
a+c # a & c must have a compatible shape
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[20], line 2
      1 c = np.array( [[1, 1, 2], [0, 1, 2]] )
----> 2 a+c # a & c must have a compatible shape

ValueError: operands could not be broadcast together with shapes (2,2) (2,3) 

Matrix oriented usage¶

  • Creating 2D matrices from orthogonal 1D vectors
  • Global tests over an multidimensional array
  • Mathematical expressions using N-arrays instead of scalars
  • Slicing…

Creating 2D matrices from orthogonal 1D vectors¶

Transposing a 1D vector to make it columnar:

In [21]:
row = np.arange(3)
print(row)
column = row[:, np.newaxis]
print(column)
[0 1 2]
[[0]
 [1]
 [2]]

Any mathematical expression using a row and a column will create a 2D matrix:

In [22]:
row+column
Out[22]:
array([[0, 1, 2],
       [1, 2, 3],
       [2, 3, 4]])
In [23]:
np.exp(row)*np.exp(column)
Out[23]:
array([[ 1.        ,  2.71828183,  7.3890561 ],
       [ 2.71828183,  7.3890561 , 20.08553692],
       [ 7.3890561 , 20.08553692, 54.59815003]])

Global tests over an multidimensional array¶

The logical operators applied to N-array produce an N-array of booleans.

In [24]:
mat = np.arange(3*2).reshape(3, 2)
print(mat)
cond = mat<3
print(cond)
[[0 1]
 [2 3]
 [4 5]]
[[ True  True]
 [ True False]
 [False False]]

Because False is interpreted as 0 when involved in a numerical operation, an ndarray of booleans can be used to set to 0 elements of another matrix.

In [25]:
x = np.random.rand(3, 2)
print(x)
result = x*cond
print(result)
[[0.37058439 0.27492504]
 [0.59183055 0.61527709]
 [0.05840027 0.11723157]]
[[0.37058439 0.27492504]
 [0.59183055 0.        ]
 [0.         0.        ]]

Mathematical expressions using wether N-arrays or scalars¶

The numpy functions can also receive some scalar values and return scalar results:

In [26]:
def my_function(x):
    return np.sin(np.exp(x))
In [27]:
my_function(np.arange(3))
Out[27]:
array([0.84147098, 0.41078129, 0.89385495])
In [28]:
my_function(12.0)
Out[28]:
0.991769422460002

Slicing¶

Quite the same as for built-in sequences, one can use slices for read and write. Below, we extend a 2D array by adding null elements all around:

In [29]:
matrix = np.arange(6).reshape(2, 3)
print(matrix)

print()
ext_shape = np.array(matrix.shape)+2
ext_matrix = np.zeros(ext_shape)
print(ext_matrix)

print()
ext_matrix[1:-1, 1:-1] = matrix
print(ext_matrix)
[[0 1 2]
 [3 4 5]]

[[0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]]

[[0. 0. 0. 0. 0.]
 [0. 0. 1. 2. 0.]
 [0. 3. 4. 5. 0.]
 [0. 0. 0. 0. 0.]]

Questions ?¶

See also

  • http://www.numpy.org
  • https://docs.scipy.org/doc/numpy/user/quickstart.html
  • http://math.mad.free.fr/depot/numpy/base.html
  • http://www.labri.fr/perso/nrougier/teaching/numpy.100/