Indexing and views
Use array shapes, broadcasting and reductions to express a small data transformation.
THE IDEA
Two arrays, one block of memory
Copying a big array is slow and uses memory, so NumPy avoids it when it can. A slice such as a[:, 1:3] does not copy: it creates a new array object that looks at the same memory with different bounds. That is a view. Write into the view and you write into the original.
Basic indexing (integers, slices, :, steps) gives views. Advanced indexing (a list of positions, or a boolean mask) must gather scattered cells into a fresh array, so it gives a copy. Transpose and, on contiguous data, reshape are also views.
b = a[:, 1:3]
Writing through an index is different from reading with one
A fancy index on the left of an assignment writes into the original: a[a > 6] = 0 zeroes those cells of a itself. The same index on the right(b = a[a > 6]) builds a copy, and changing b afterwards never reaches a.
Predict first. With a = np.arange(12).reshape(3, 4), you run b = a[a > 6] and then b[0] = 99. How many cells of a change?
The common mistake: an in-place edit on a slice you did not mean to share
>>> x = np.array([[1, 2], [3, 4]])
>>> y = x[:, 0] # first column, a view
>>> y *= 2
>>> x
array([[2, 2],
[6, 4]]) # x changed, although we only 'used' y
>>> z = x[:, 0].copy() # an independent copy
>>> z *= 2 # x is untouchedAnd plain assignment copies nothing at all: b = a just gives the same array a second name.
Chapter context
A tensor is a multidimensional array with a shape and element type. Many AI bugs come from doing a valid operation along the wrong axis. Write the intended dimensions before trying to shorten the code.
TRY IT YOURSELF
- zero_row_copy(a, i) returns a new array with row i set to 0. The caller's array must stay untouched.
- double_column_inplace(a, j) multiplies column j of a by 2 in place and returns None. It must also work when a is itself a slice of a bigger array.
- is_view_of(base, other) says whether the two arrays share memory. clamp_negatives_inplace(a) replaces every negative entry of a by 0, in place.
Stuck, or something not working? You can come back to it any time.
CHECK YOUR UNDERSTANDING
Why check a sliced array before editing it in place?
Chapter reference: math, worked example & code
This section belongs to the whole chapter, so it is the same on every lesson in it and may cover a different lesson's topic. The code for the experiment you just ran is inside the experiment itself.
Math and notation
For a data matrix , feature means are
Here i indexes examples and j indexes features. The mean vector has d entries, so subtracting it from X broadcasts along rows.
Worked example
For X = [[1, 2], [3, 4]], the feature means are [2, 3]. Centering produces [[-1, -1], [1, 1]]. Each centered column has mean zero. Computing row means instead would answer a different question even though the operation is valid.
Reference code
The following example uses the Python standard library and does not call a remote service.
X = [[1, 2], [3, 4]]
means = [sum(row[j] for row in X) / len(X) for j in range(2)]
centered = [[x - m for x, m in zip(row, means)] for row in X]
assert means == [2, 3]
assert centered == [[-1, -1], [1, 1]]
Python examples are provided for study and local execution; this page does not execute Python.
Common mistakes
Broadcasting is a shape rule, not permission to ignore axis meanings. Vectorized code can create large intermediate arrays. Normalize training and test data with training statistics only.