Introduction To Numerical Computing With Numpy Manual
Introduction To Numerical Computing With Numpy Manual
Numerical Computing
with Numpy
Use Restrictions:
Copy, disclose, transfer or distribute ETM to any party in any form. Remove,
modify or obscure any copyright, trademark, legal notices or other
proprietary notations in ETM. Make derivative works of ETM or combine ETM or
any part of ETM with any other works. Use ETM in any manner that could be
detrimental to Enthought. © 2001-2022, Enthought, Inc. All Rights
Reserved. All trademarks and registered trademarks are the property of their
respective owners.
Q3-2022
letter
3.5.5
Introduction to Numerical Computing with
Numpy
Enthought, Inc.
www.enthought.com
Introduction 1
NumPy 2
Introducing NumPy Arrays 4
Multi-Dimensional Arrays 8
Slicing/Indexing Arrays 10
Fancy Indexing 16
Creating arrays 19
Array Creation Functions 21
Array Calculation Methods 24
Array Broadcasting 33
Universal Function Methods 41
The array data structure 48
Creating arrays 51
Closing words 56
Appendix 57
About Enthought 58
Introduction to
Numerical Computing
with NumPy
SciPy Conference Tutorial
2022
NumPy
The Standard Numerical Library
for Python
2
NumPy: The Standard Numerical Library for Python
Syllabus
1. Introducing Arrays
2. Indexing and Slicing
3. Creating Arrays
4. Array Calculations
5. The Array Data Structure
6. Structure Operations
a = 0 1 2 3
NumPy
Introducing Arrays
4
Introducing NumPy Arrays
SIMPLE ARRAY CREATION ARRAY SHAPE
>>> a = np.array([0, 1, 2, 3]) # Shape returns a tuple listing the
>>> a # length of the array along each
array([0, 1, 2, 3]) # dimension.
>>> a.shape
CHECKING THE TYPE (4,)
>>> type(a)
BYTES PER ELEMENT
numpy.ndarray
>>> a.itemize
NUMERIC "TYPE" OF ELEMENTS 4
>>> a.dtype
BYTES OF MEMORY USED
dtype('int32')
# Return the number of bytes used by
NUMBER OF DIMENSIONS # the data portion of the array.
>>> a.nbytes
>>> a.ndim
16
1
Array Operations
SIMPLE ARRAY MATH MATH FUNCTIONS
>>> a = np.array([1, 2, 3, 4]) # create array from 0.0 to 10.0
>>> b = np.array([2, 3, 4, 5]) >>> x = np.arange(11.0)
>>> a + b
array([3, 5, 7, 9]) # multiply entire array by scalar
# value
>>> a * b >>> c = (2.0 * np.pi) / 10.0
array([ 2, 6, 12, 20]) >>> c
0.62831853071795862
>>> a ** b >>> c * x
array([ 1, 8, 81, 1024]) array([0. , 0.628, …, 6.283])
# in-place operations
>>> x *= c
NumPy defines these constants: >>> x
pi = 3.14159265359 array([0. , 0.628, …, 6.283])
e = 2.71828182846
# apply functions to array
>>> y = np.sin(x)
6
Setting Array Elements
ARRAY INDEXING ! BEWARE OF TYPE COERCION
>>> a[0] >>> a.dtype
0 dtype('int32')
index 0 1 2 3
Multi-Dimensional Arrays
MULTI-DIMENSIONAL ARRAYS ARRAY SHAPE
>>> a = np.array([[ 0, 1, 2, 3], >>> a[1, 3]
... [10,11,12,13]]) 13
column
>>> a 2D Array row
array([[ 0, 1, 2, 3], 0 1 2 3 >>> a[1, 3] = -1
a
[10,11,12,13]]) 10 11 12 13 >>> a
array([[ 0, 1, 2, 3],
SHAPE – (ROWS, COLUMNS) [10,11,12,-1]]) 0
a 1 0 1 2 3
>>> a.shape dim 1 4 10 11 12 -1
0 1 2 3
(2, 4) dim 0 a 2
10 11 12 13
0 1 2 3
>>> a.size 4
>>> a[1]
0 1 2 3
8 2 x 4 = 8 a 2
10 11 12 13 array([10, 11, 12, -1])
0
0 1 2 3
NUMBER OF DIMENSIONS a 1
10 11 12 -1
>>> a.ndim dim 1 0 1 2 3
0 1 2 3
2 dim 0 a
10 11 12 13
8
Formatting Numeric Display
DEFAULT FORMATTING USER FORMATTING
>>> a = np.arange(1.0, 3.0, 0.5) # set precision
>>> a >>> np.set_printoptions(
array([1. , 1.5, 2. , 2.5]) precision=2)
>>> a
>>> a * np.pi
array([1. , 1.5, 2. , 2.5])
array([3.14159265, 4.71238898, 6.28318531,
7.85398163]) >>> a * np.pi
array([3.14, 4.71, 6.28, 7.85])
>>> a * np.pi * 1e8
>>> a * np.pi * 1e8
array([3.14159265e+08, 4.71238898e+08,
array([3.14e+08, 4.71e+08, 6.28e+08,
6.28318531e+08, 7.85398163e+08])
7.85e+08])
>>> a * np.pi * 1e-6 >>> a * np.pi * 1e-6
array([3.14159265e-06, 4.71238898e-06, array([3.14e-06, 4.71e-06, 6.28e-06,
6.28318531e-06, 7.85398163e-06]) 7.85e-06])
# suppress scientific notation
>>> np.set_printoptions(
suppress=True)
>>> a * np.pi * 1e-6
array([0., 0., 0., 0.])
9
0 1 2 3 4 5
0
0 1 2 3 4 5
1
10 11 12 13 14 15
2
20 21 22 23 24 25
3
30 31 32 33 34 35
4
40 41 42 43 44 45
5
50 51 52 53 54 55
NumPy
Indexing and Slicing
10
Slicing
var[lower:upper:step]
• Extracts a portion of a sequence by specifying a lower and upper bound.
• The lower-bound element is included, but the upper-bound element is not included.
• Mathematically: [lower, upper). The step value specifies the stride between elements.
Array Slicing
SLICING WORKS MUCH LIKE STANDARD
PYTHON SLICING
0 1 2 3 4 5
>>> a[0, 3:5]
array([3, 4]) 0
0 1 2 3 4 5
>>> a[4:, 4:] 1
10 11 12 13 14 15
array([[44, 45], 2
[54, 55]]) 20 21 22 23 24 25
3
>>> a[:, 2] 30 31 32 33 34 35
4
array([2, 12, 22, 32, 42, 52])
40 41 42 43 44 45
5
SLICING ARRAYS 50 51 52 53 54 55
>>> a[2::2, ::2]
array([[20, 22, 24],
[40, 42, 44]])
Give it a try!
a = np.arange(25).reshape(5, 5)
0 1 2 3 4
0
0 1 2 3 4
1
5 6 7 8 9
2
10 11 12 13 14
3
15 16 17 18 19
4
20 21 22 23 24
5
© 2008-2022 Enthought, Inc. 14
14
Sliced Arrays Share Data
Arrays created by slicing share data with the originating array.
Changing values in a slice also changes the original array.
# changing b changed a!
>>> a
array([ 0, 1, 10, 3, 4])
>>> np.shares_memory(a, b)
True
15
Fancy Indexing
INDEXING BY POSITION INDEXING WITH BOOLEANS
>>> a = np.arange(0, 80, 10) # manual creation of masks
>>> mask = np.array(
# fancy indexing ... [0, 1, 1, 0, 0, 1, 0, 0],
>>> indices = [1, 2, -3] ... dtype=bool)
>>> y = a[indices]
>>> y # fancy indexing
array([10, 20, 50]) >>> y = a[mask]
>>> y
# this also works with setting array([99, 99, 99])
>>> a[indices] = 99
>>> a
array([0, 99, 99, 30, 40, 99, 60, 70])
-3 -2 -1
0 1 2 3 4 5 6 7
a 0 10 20 30 40 50 60 70
y 10 20 50
16
Fancy Indexing in 2-D
>>> a[[0, 1, 2, 3, 4],
... [1, 2, 3, 4, 5]]
0 1 2 3 4 5
array([ 1, 12, 23, 34, 45])
Give it a try!
0 1 2 3 4
0
0 1 2 3 4
1
5 6 7 8 9
2
10 11 12 13 14
3
15 16 17 18 19
4
20 21 22 23 24
5
© 2008-2022 Enthought, Inc. 18
18
arange()
linspace()
array()
zeros()
ones()
NumPy
Creating Arrays
0 1 2 3
REDUCING PRECISION
a 0 1 2 3
>>> a = np.array([0,1.,2,3],
... dtype='float32') 1 byte 1 byte 1 byte 1 byte =4
>>> a.dtype
dtype('float32') Base 2 Base 10
>>> a.nbytes 00000000 -> 0 = 0*2**0 + 0*2**1 + ... + 0*2**7
16 00000001
00000010
->
->
1 = 1*2**0 + 0*2**1 + ... + 0*2**7
2 = 0*2**0 + 1*2**1 + ... + 0*2**7
...
11111111 -> 255 = 1*2**0 + 1*2**1 + ... + 1*2**7
-1
1
0 -2
1 2 3 6
4 5 6 15
5 7 9
NumPy
Array Calculation Methods
24
Computations with Arrays
25
Multi-Dimensional Arrays
VISUALIZING MULTI-DIMENSIONAL ARRAYS
0 1
0 1 2 3
0 1 2
-3 -3
-1 -1 -1 -1
-2 -2 -2
-4
26
Array Calculation
Methods 1 2 3
4 5 6
SUM METHOD
np.sum(a)
# Methods act on data stored in the array
>>> a = np.array([[1,2,3], -1
[4,5,6]]) 1
1 2 3
0 -2
# .sum() defaults to adding up all the
4 5 6
# values in an array.
>>> a.sum()
21 5 7 9
# supply the keyword axis to sum along the np.sum(a, axis=0)
# 0th axis -1
>>> a.sum(axis=0) 1
array([5, 7, 9]) 1 2 3 6
0 -2
# supply the keyword axis to sum along the 4 5 6 15
# last axis
np.sum(a, axis=-1)
>>> a.sum(axis=-1)
array([ 6, 15])
© 2008-2022 Enthought, Inc. 27
27
28
Min/Max
MIN ARGMIN/MAX
>>> a = np.array([[2, 3], [0, 1]]) # Many tasks (like optimization) are
# Prefer NumPy functions to builtins when # interested in the location of a min/max,
# working with arrays # not the value
>>> np.min(a) >>> a.argmax()
0 1
# Most NumPy reducers can be used as
# methods as well as functions # arg methods return the location in a 1D,
>>> a.min() # flattened version of the original array
0 >>> np.argmin(a)
2
MAX UNRAVELING
# Use the axis keyword to find max values # NumPy includes a function to un-flatten
# for one dimension # 1D locations
>>> a.max(axis=0) >>> np.unravel_index(
array([2, 3]) ... a.argmax(), a.shape)
# as a function (0, 1)
>>> np.max(a, axis=1)
array([3, 1])
29
Where
COORDINATE LOCATIONS CONDITIONAL ARRAY CREATION
# NumPy's where function has two # Where can also be used to construct a new
# distinct uses. One is to provide # array by choosing values from other
# coordinates from masks. # arrays of the same shape.
>>> positives = np.arange(1, 5)
>>> a = np.arange(-2, 2) ** 2
>>> negatives = -positives
>>> a >>> np.where(mask, positives,
array([4, 1, 0, 1]) ... negatives)
>>> mask = a % 2 == 0 array([1, -2, 3, -4])
>>> mask
array([ True, False, True, False]) # Or from scalar values. This can be useful
# for recoding arrays.
# Coordinates are returned as a tuple >>> np.where(mask, 1, 0)
array([1, 0, 1, 0])
# of arrays, one for each axis.
>>> np.where(mask) # Or from both.
(array([0, 2]),) >>> np.where(mask, positives, 0)
array([1, 0, 3, 0])
30
Statistics Array Methods
MEAN STANDARD DEV./VARIANCE
>>> a = np.array([[1,2,3], # Standard Deviation
... [4,5,6]]) >>> a.std(axis=0)
array([ 1.5, 1.5, 1.5])
# mean value of each column # For sample, set ddof=1
>>> a.mean(axis=0) >>> a.std(axis=0, ddof=1)
array([ 2.5, 3.5, 4.5]) array([ 2.12, 2.12, 2.12])
>>> np.mean(a, axis=0)
array([ 2.5, 3.5, 4.5])
# variance
>>> a.var(axis=0)
array([2.25, 2.25, 2.25])
>>> np.var(a, axis=0)
array([2.25, 2.25, 2.25])
31
Give it a try!
0 1 2 3 4 5
0
225 196 169 144 121 100
1
81 64 49 36 25 16
2
9 4 1 0 1 4
3
9 16 25 36 49 64
4
81 100 121 144 169 196
NumPy
Array Broadcasting
Array Broadcasting
NumPy arrays of different dimensionality can be combined in the same expression. Arrays with smaller
dimension are broadcasted to match the larger arrays, without copying data.
4x3 3
0 0 0 0 1 2 0 0 0 0 1 2 0 1 2
10 10 10 + = 10 10 10 + 0 1 2
= 10 11 12
20 20 20 20 20 20 0 1 2 20 21 22
30 30 30 30 30 30 0 1 2 30 31 32
stretch
4x1 3
0 0 1 2 0 0 0 0 1 2
10 + = 10 10 10 + 0 1 2 =
20 20 20 20 0 1 2
30 30 30 30 0 1 2 stretch
stretch
© 2008-2022 Enthought, Inc. 35
Broadcasting Rules
The trailing axes of either arrays must be 1 or both must have the same size for broadcasting to
occur.
Otherwise, a
"ValueError: shape mismatch: objects cannot be broadcast to a single shape"
exception is thrown.
4x3 Mismatch! 4
0 0 0 0 1 2 3
10 10 10 +
20 20 20
30 30 30
a b
4x1 3
0 0 0 0 1 2 0 1 2
10 10 10 + 0 1 2 = 10 11 12
20 20 20 0 1 2 20 21 22
30 30 30 0 1 2 30 31 32
stretch stretch
Broadcasting Indices
Broadcasting can also be used to slice elements from different “depths” in a 3-D
(or any other shape) array. This is a very powerful feature of indexing.
0
3 0 1 2
33 10 11 12
63 20 21 22
93 30 31 32
NumPy
Universal Function Methods
>>> op.reduce(a,axis=0)
>>> op.accumulate(a,axis=0)
>>> op.outer(a,b)
>>> op.reduceat(a,indices)
op.reduce()
For multidimensional arrays, op.reduce(a,axis) applies op to the elements of a along the
specified axis. The resulting array has dimensionality one less than a. The default value for
axis is 0.
SUMMING UP EACH ROW SUM COLUMNS BY DEFAULT
>>> a = np.arange(3) + np.arange(0, 40, >>> np.add.reduce(a)
... 10).reshape(-1, 1) array([60, 64, 68])
>>> np.add.reduce(a,1)
array([ 3, 33, 63, 93])
1 1
60 64 68
0 0
3 0 1 2 0 1 2
33 10 11 12 10 11 12
63 20 21 22 21 22 23
93 30 31 32 30 31 32
op.reduceat()
op.reduceat(a,indices) applies op to EXAMPLE
ranges in the 1-D array a defined by the values in >>> a = np.array([0,10,20,30,40,50])
indices. The resulting array has the same >>> indices = np.array([1,4])
>>> np.add.reduceat(a,indices)
length as indices. array([60, 90])
0 1 2 3 4 5
For example:
y = add.reduceat(a, indices) 0 10 20 30 40 50
indices[i + 1]
y[i] = a[n]
n = indices[i]
For multidimensional arrays, reduceat() is always
Unlike
applied alongslicing,
the lastfancy indexing
axis (sum creates
of rows copies
for 2-D
! arrays). This is of
instead different fromoriginal
a view into the default
array.for
reduce() and accumulate().
Memory Block
0 1 2
8 bytes
24 bytes
NumPy
The Array Data Structure
48
Array Data Structure
Memory Block
0 1 2 3 4 5 6 7 8
0 1 2
Python View: 3 4 5
6 7 8
49
8 bytes
24 bytes
0 1 2
Python View: 3 4 5
6 7 8
50
0 1
a 2 3
b 10 1 2 3
NumPy
Structure Operations
0 1 2
0 1 2 3 4 5
0
0 1 2 Two
a 0 1 2 3 4 5 b 1 Rows
3 4 5
This is not a new copy of the data.
The original data does not get reordered.
© 2008-2022 Enthought, Inc. 52
52
Transpose
TRANSPOSE TRANSPOSE RETURNS VIEWS
>>> a = np.array([[0,1,2], # Transpose does not move values around in
... [3,4,5]]) # memory. It only changes the order of
>>> a.shape # "strides" in the array
(2,3) >>> a.strides
(24, 8)
# Transpose swaps the order of axes. >>> a.T.strides
>>> a.T (8, 24)
array([[0, 3], Memory Block
[1, 4], 8
24
[2, 5]]) 0 1 2 3 4 5
>>> a.T.shape
(3,2) 8 bytes
24 bytes
Two Columns
Three Columns 3 2
0 1 strides 24 8 strides 8 24
0 1 2 0 24
8
a 1 0 3 Three
0 Two 0 1 2 8 0 3
a 0 1 2 1 4 Rows 2 24
1 Rows 2 3 4 5 3 1 4
3 4 5 2 5
2x3 2 5
3x2
Reshaping Arrays
RESHAPE SHAPE
>>> a = np.array([[0,1,2], >>> a = np.arange(6)
... [3,4,5]]) >>> a
array([0, 1, 2, 3, 4, 5])
# Return a new array with a different shape >>> a.shape
# (a view where possible) (6,)
>>> a.reshape(3,2)
array([[0, 1], # Reshape array in-place to 2x3
[2, 3], >>> a.shape = (2,3)
[4, 5]]) >>> a
array([[0, 1, 2],
# Reshape cannot change the number of [3, 4, 5]])
# elements in an array
>>> a.reshape(4,2)
ValueError: total size of new array must be Six Elements Three Columns
unchanged
0 1 2
0 1 2 3 4 5
0
0 1 2 Two
a 1 Rows
0 1 2 3 4 5 3 4 5
54
Flattening Arrays
FLATTEN (SAFE) RAVEL (EFFICIENT)
a.flatten() converts a multi-dimensional array a.ravel() is the same as a.flatten(), but
into a 1-D array. The new array is a copy of the returns a reference (or view) of the array if possible
original data. (i.e., the memory is contiguous). Otherwise the new
array copies the data.
# Create a 2D array np.ravel() can be applied to non-array objects.
>>> a = np.array([[0,1],
... [2,3]]) # Flatten out elements to 1-D
# Flatten out elements to 1D >>> b = a.ravel()
>>> b = a.flatten() >>> b
>>> b array([0,1,2,3])
array([0,1,2,3])
# Changing b does change a
# Changing b does not change a >>> b[0] = 10
>>> b[0] = 10 >>> b
>>> b array([10,1,2,3])
array([10,1,2,3]) b 10 1 2 3 >>> a changed! b 10 1 2 3
>>> a no change
0 1 array([[10, 1], 10 1
array([[0, 1], a 2 3 [ 2, 3]])
a 2 3
[2, 3]])
© 2008-2022 Enthought, Inc. 55
Stay in touch!
Enthought
Enthought @enthought
Media
EuroSciPy
57
Enthought powers
digital transformation
for science.
ABOUT ENTHOUGHT
We empower scientists.
Equipping scientists with digital skills and technology