Download An Introduction to NumPy: Array Operations and Broadcasting and more Exams Logic in PDF only on Docsity!
NumPy
Provides:
- true n-dimensional arrays (careful: 1-D arrays are not 1-D matrices)
- operations on those arrays: math, logical, sorting, etc
- discrete Fourier transform
- basic linear algebra
- basic statistics
- basic simulation Arrays ( ndarray )
- Fixed size: size changing involves copying and deletion of older array
- Homogeneous: all elements of the same type
but that type could be “Python object”, so it may be a size changing object,
of course obtained through indirection: it is not the intended use, however
Universal functions ( ufunc )
operate in a uniform way on those arrays, usually element-wise (element per
element)
Two main mechanisms:
vectorization: loops are implicit
broadcasting: in certain situations the shape of an array is “adapted” to the
context
import numpy as np
Preliminary examples: (file lez- 1 .py)
a=np.array([1,2,3])
b=np.array([4,5,6]) c=a+b
instead of the loop [vectorisation of a universal function]
c=[]
for i in len(a): c.append(a[i]*b[i])
if a and b are multidimensional, nested loop
broadcasting:
d=np.array([10])
e=d+a e=array([11,12,13])
f=10+a f=array([11,12,13])
They may obtained through attributes of the ndarray objects:
C.ndim x.ndim always equal to len(x.shape)
C.shape
C.size the number of elements: prod(x.shape)
[prod available in Python 3.8]
C.dtype the dtype of each scalar object
Creating arrays
np.zeros((3,2)) the arg must be a shape
return a zero matrix, dtype=float
np.ones((3,2)) return an all-one matrix, dtype=float
np.empty((3,2)) return an uninitialized matrix, dtype=float
All these functions may take the optional named parameter dtype=…
NumPy arrays from standard sequences “array like”:
x = np.array([2,3,1,0]) x = np.array([[1,2.0],[0,0],(1+1j,3.)])
note mix of tuple and lists, and types
x array([[1.+0.j, 2.+0.j], [0.+0.j, 0.+0.j], [1.+1.j, 3.+0.j]]) x.dtype dtype('complex128') type(x) <class 'numpy.ndarray'>
But careful: if the shape is not correct we will get “strange” results:
np.array(([1,2,3,4],[5,6])) array([list([1, 2, 3, 4]), list([5, 6])], dtype=object)
Arange :
np.arange(first,last,step) like range, but returns
a 1 - dim array, dtype=int last and step are optional Same as np.array(range(…)) np.arange(10,30,5) array([10,15,20,25])
We may use the reshape method to give a shape to a certain array:
np.arange(10,30,5).reshape((2,2)) array([[10, 15], [20, 25]])
v=np.arange(18).reshape((6,3)) array([[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11], [12, 13, 14], [15, 16, 17]]) v.reshape((3,3,2)) array([[[ 0, 1], [ 2, 3], [ 4, 5]], [[ 6, 7], [ 8, 9], [10, 11]], [[12, 13], [14, 15], [16, 17]]])
Of course the shape must match the size of the base array.
[reshape gives a view on the base array ; does not create a new array: more
later]
arange accepts float arguments, even a float step
The dtype of the created array object depends (more or less in the obvious way)
from the types of the arguments of arange
In the case of a float step, the size of the created object is non obvious, since it
depends on approximations:
from numpy import pi np.arange(pi, 3pi, pi) array([pi, 2pi]) np.arange(pi,3pi+10-15, pi) array([pi, 2pi 3pi]) np.arange(pi,3pi+10 ****- 16* , pi) array([pi, 2pi])
More useful is linspace which generates an uniformly spaced array:
np.linspace(0,2,9) 9 numbers from 0 to 9 (included)
array([0., 0.25, 0.5 , 0.75, 1., 1.25, 1.5 , 1.75, 2.])
c array([[ 6, 8], [10, 12], [14, 16]]) c1=c.sum(axis=1)
c1.shape we project along axis 1, so:
c array([[ 6, 9 ], [ 24 , 27]]) c2=c.sum(axis=2)
c2.shape we project along axis 2, so:
c array([[ 1, 5, 9 ], [ 13 , 17, 21]])
Some universal functions:
np.exp(a) for any element x, computes e^x
np.exp 2 (a) for any element x, computes 2^x
np.expm1(a) for any element x, computes e^x - 1
This function provides greater precision than exp(x) - 1 for small values of x.
No axis parameter may be given on these.
See:
https://docs.scipy.org/doc/numpy/reference/routines.math.html
x
Boolean operations as universal functions
For problems of too low level to be discussed here, the usual Boolean functions
(not, and, or) cannot be used as universal functions on arrays. Example:
Example:
x array([[21., 19., 18., 3.], [ 3., 4., 19., 21.]]) x> array([[ True, True, True, False], [False, False, True, True]]) not (x>4) Traceback (most recent call last): File "<pyshell#330>", line 1, in not (x>4) ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() ~(x>4) array([[False, False, False, True],
[ True, True, False, False]])
Therefore some functions are redefined for this. Use:
~ for not
& for and
| for or
(x>4) and (x==4) Traceback (most recent call last): File "<pyshell#336>", line 1, in (x>4) and (x==4) ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() (x>4) & (x==4) array([[False, False, False, False], [False, False, False, False]])
NumPy re-defines Booleans values (like it redefines integers “array scalars”).
np.True_ np.False_
Their “type”:
type(np.True_) <class 'numpy.bool_'>
Their dtype:
np.True_.dtype dtype('bool')
The reason for this seems to be the fact that Python does not provide any
'xxx' special methods corresponding to the 'and', 'or' and 'not' boolean operators
(contrary to other operations like +, *, or ==).
[PEP 335:
Axis
The j-axis of an array is the component of the array when you see its elements
as coordinates in a cartesian coordinate system:
I would start rows and columns at 0
Example:
For a 2-dim array:
axis 0: running vertically across rows (that is: columns)
axis 1: running horizontally across columns (that is: rows)
Some operations take an axis as a (often optional) parameter
Example:
v=np.arange(10).reshape(2,5) print('v: ', v) v: [[0 1 2 3 4] [5 6 7 8 9]] print('np.sum(v): ', np.sum(v)) np.sum(v): 45 print('np.sum(v, axis=0): ', np.sum(v, axis=0)) np.sum(v, axis=0): [ 5 7 9 11 13] print('np.sum(v, axis=1): ', np.sum(v, axis=1)) np.sum(v, axis=1): [10 35]
For sum, the default is axis None (along all axes)
The same function on 3-D:
We are summing along an axis, then the result will have as shape the original
shape without the dimension over which we are summing:
t=np.arange(12).reshape(2,2,3)
[[[ 0 1 2]
[ 3 4 5]]
[[ 6 7 8]
[ 9 10 11]]]
print('np.sum(t, axis=0): ') result of shape (2,3)
[[ 6 8 10]
[12 14 16]]
print('np.sum(t, axis=1): ') result of shape (2,3)
[[ 3 5 7]
[15 17 19]]
print('np.sum(t, axis=2): ') result of shape (2,2)
[[ 3 12]
[21 30]]