Arrays in NumPy
Read these first if they are new to you
- Reading Python Basic
- Vectors: arrows made of numbers Basic
The idea in one paragraph
A NumPy array is a grid of numbers that all have the same type. Its shape says how many numbers lie along
each direction: four points in 3D make an array of shape (4, 3), one row per point. Square brackets pick rows,
columns or blocks. Arithmetic on an array acts on every number at once, and functions such as sum and
mean can collapse one direction. One line of array code replaces a loop, and it runs much faster.
A table of points is an array with two axes
Take four corners of a box, each a vector with x, y and z. Write them as a table: one row per point, one column per coordinate. NumPy stores that table as an array, a block of numbers of one type laid out in a grid.
Each direction of the grid is an axis. Axis 0 runs down the rows, and axis 1 runs across the columns.
The shape lists the length along each axis, so this table has shape (4, 3). The number of
axes is ndim. The dtype is the type of every number: float64 means decimal
numbers stored in 64 bits.
shape.py
import numpy as np
pts = np.array([[0.0, 0.0, 0.0],
[2.0, 0.0, 0.0],
[2.0, 4.0, 0.0],
[0.0, 4.0, 2.0]])
print(pts.shape, pts.ndim, pts.dtype)
print(pts[2]) # one row: the third point
print(pts[:, 1]) # one column: every y
print(pts[1:3, :2]) # rows 1 and 2, columns 0 and 1
(4, 3) 2 float64
[2. 4. 0.]
[0. 0. 4. 4.]
[[2. 0.]
[2. 4.]]
Brackets pick rows first, then columns
Inside the brackets, a comma separates the axes: pts[row, column]. Each part can be one index, a
slice such as 1:3 (from 1 up to, but not including, 3), or a bare : for "all of them". If
you give only one part, NumPy takes all the columns. Reading Python covers
indexes and slices for plain lists.
Predict the highlighted cells before you press a button. Then find the expression that picks the x and y of every point, and only those.
| col 0 (x) | col 1 (y) | col 2 (z) |
|---|
pts[2] is a single row of shape
(3,), and pts[-1, 2] is one number. A slice keeps its axis, even if it holds one
item.Arithmetic on an array acts on every number
pts * 10 multiplies each of the 12 numbers by 10. pts + pts adds the two arrays number by
number, in matching positions. These are elementwise operations. No loop appears in your code, but NumPy
runs one inside, in fast compiled code.
That inner loop is why arrays matter. On the computer that ran these snippets, a Python loop that found the length of a million 3D points took about 0.3 seconds. The one-line array version, shown below, took about 0.015 seconds: about 20 times faster.
pts * 10 combines an array with a single number. NumPy can also combine some arrays of different
shapes, such as a table of points and one point. That rule is broadcasting.
axis=0 collapses the rows; axis=1 collapses the columns
Functions such as sum, mean and max can combine numbers along one axis. The
axis you name is the one that disappears. pts.sum(axis=0) adds down each column and leaves one number per
column. pts.sum(axis=1) adds across each row and leaves one number per point.
The centroid of some points is their average position: the mean of the x values, of the y values and of the z values. For the four points above:
- Add down each column: x gives 0 + 2 + 2 + 0 = 4, y gives 0 + 0 + 4 + 4 = 8, z gives 0 + 0 + 0 + 2 = 2.
- Divide by the 4 points: the centroid is (1, 2, 0.5).
- In NumPy that is one call,
pts.mean(axis=0), because it averages down the rows.
Each point's distance from the origin uses the other axis. Square every number, add across each row with
axis=1, then take the square root. For the third point that is √(2² + 4² + 0²) = √20 ≈ 4.47.
axis.py
import numpy as np
pts = np.array([[0.0, 0.0, 0.0],
[2.0, 0.0, 0.0],
[2.0, 4.0, 0.0],
[0.0, 4.0, 2.0]])
print(pts * 10) # every number times 10
print(pts.sum(axis=0)) # add down each column
print(pts.mean(axis=0)) # the center of the points
print(np.sqrt((pts ** 2).sum(axis=1))) # each point's distance from the origin
[[ 0. 0. 0.]
[20. 0. 0.]
[20. 40. 0.]
[ 0. 40. 20.]]
[4. 8. 2.]
[1. 2. 0.5]
[0. 2. 4.47213595 4.47213595]
A slice such as pts[:, 1] is usually a view: it shares memory with pts, so
changing it changes pts too. Call .copy() when you need a separate array. Also, arrays can
have more than two axes. A batch of 8 clouds of 2048 points has shape (8, 2048, 3), and
axis=-1 names the last axis.
Check yourself
-
An array
cloudhas shape(1000, 3). What are the shapes ofcloud[:, 2],cloud[:10]andcloud.max(axis=0)?Answer
(1000,): every z value.(10, 3): the first ten points.(3,): the largest x, the largest y and the largest z, because axis 0 disappears. -
Now try a worked example of your own. For the points (1, 1, 0), (3, 1, 0) and (2, 4, 3), find the centroid by hand. Which NumPy call gives it?
Answer
Add down the columns: (6, 6, 3). Divide by 3: (2, 2, 1). The call is
pts.mean(axis=0). -
You want the height of every point above the floor, which is its z value. Someone writes
pts[2]. What does that give instead, and what is the fix?Answer
pts[2]is the third point, all three coordinates. The z values are column 2 of every row:pts[:, 2].
Go further
Optional background, with more pictures and more functions.
-
Colored drawings of picking rows and columns. The next part, "Matrix Aggregation", draws sums along an axis.
-
NumPy: the absolute basics for beginners, Indexing and slicing NumPy documentation Tutorial Intermediate
The official beginner guide. Read on to its sections on array operations and broadcasting.
Where this shows up
Units that build on this one
- PyTorch tensors on the GPU Intermediate
- Shapes as point clouds Intermediate
- 3D images made of voxels Intermediate
- Broadcasting: arrays of different shapes Intermediate
- Floating-point numbers: rounding to the nearest stored value Intermediate