Choose the Readings Without Losing Their Place
Botie may need one morning, a run of mornings, or selected greenhouses. We need to express each request precisely and know whether editing the selection will change the original report.
13 sections · 5 questions · 2 coding challenges
The arrow keys move between sections too.
Working on Part of a Large Scientific Record
BOTIE
NumPy distinguishes basic slicing, which can share storage, from advanced indexing, which gathers values into a new array. Those documented rules explain both the convenience of selection and the need for care when editing it.
Sources for this history
Which Part of the Report Did We Ask For?
A report with hundreds of rows is useful only if we can retrieve the observations we need. Sometimes they are adjacent. Sometimes we need particular positions in a particular order. Those requests should not be confused.
We will follow a small temperature table through slices and explicit index selections, then check which results share storage with the original. This matters whenever we prepare data while keeping the original measurements available.
The row numbers refer to the invented temperature table shown here.
Step 1 of 3
Keep the original order visible
Rows are mornings; columns are north, middle, south.
| Day | North | Middle | South |
|---|---|---|---|
| Monday | 10 | 20 | 30 |
| Tuesday | 14 | 22 | 36 |
| Wednesday | 16 | 24 | 38 |
Monday
- North
- 10
- Middle
- 20
- South
- 30
Tuesday
- North
- 14
- Middle
- 22
- South
- 36
Wednesday
- North
- 16
- Middle
- 24
- South
- 38
Step 2 of 3
A range follows existing positions
Taking the first two mornings keeps their order and stops before the third.
| Selected row | North | Middle | South |
|---|---|---|---|
| 0: Monday | 10 | 20 | 30 |
| 1: Tuesday | 14 | 22 | 36 |
0: Monday
- North
- 10
- Middle
- 20
- South
- 30
1: Tuesday
- North
- 14
- Middle
- 22
- South
- 36
Step 3 of 3
A gather follows requested positions
Requesting row two and then row zero deliberately changes the order.
| Selected row | North | Middle | South |
|---|---|---|---|
| 2: Wednesday | 16 | 24 | 38 |
| 0: Monday | 10 | 20 | 30 |
2: Wednesday
- North
- 16
- Middle
- 24
- South
- 38
0: Monday
- North
- 10
- Middle
- 20
- South
- 30
Selecting a position does not change its identity
Gather chooses the days; transpose changes which meaning occupies a row. Neither step averages or sorts the selected temperatures.
Which days did Botie actually ask for?
The requested row numbers may repeat or arrive out of order. Follow one request to its original day, then check where that day's readings appear in the result.
BOTIE
Selected readings, arranged by greenhouse
| 16 | 10 |
| 24 | 20 |
| 38 | 30 |
Follow the operations
1. Days by greenhouse
10 20 30 14 22 36 16 24 38 2. Requested day indices
- 02
- 10
3. Gather selected entries
16 24 38 10 20 30 4. Swap rows and columns
16 10 24 20 38 30 5. Result
16 10 24 20 38 30
These workshop wires carry values rather than shared NumPy storage. Copy and view behaviour is demonstrated and checked in Python.
1. Read a Slice From Start to Stop
A slice has a start, a stop, and an optional step. The stop is excluded. Leaving a boundary empty uses the corresponding end of the axis. A negative index counts back from the end, so minus one selects the last entry.
In a matrix we supply a selector for each axis, separated by a comma. Selecting with a single integer removes that axis; selecting a one-entry slice keeps it.
Keep a row, or keep a one-row table
These selections contain the same first-day readings, but the resulting shapes differ. The last expression selects every other greenhouse from the final day.
import numpy as np
a = np.array([[10,20,30],[14,22,36],[16,24,38]])
print(a[0].tolist())
print(a[0].shape)
print(a[0:1].shape)
print(a[-1, ::2].tolist())[10, 20, 30]
(3,)
(1, 3)
[16, 38]Keeping an axis can make a later calculation easier to align. The step of two selects columns zero and two; it does not multiply the temperatures.
2. Choose Positions in an Explicit Order
An integer index array requests positions rather than a continuous range. It can reorder entries or repeat them. For multiple axes, two index lists normally identify pairs of coordinates. If we want every combination of chosen rows and chosen columns, we need to express that different request.
Pairs of coordinates or a rectangular selection
The paired request retrieves row two, column one and row zero, column two. ix_ creates selectors for all combinations of those row and column choices.
import numpy as np
a = np.array([[10,20,30],[14,22,36],[16,24,38]])
print(a[[2, 0]].tolist())
print(a[[2, 0], [1, 2]].tolist())
print(a[np.ix_([2, 0], [1, 2])].tolist())[[16, 24, 38], [10, 20, 30]]
[24, 30]
[[24, 38], [20, 30]]The rectangle has two selected rows and two selected columns. Pairwise selection has only two entries. Neither operation is a mistake by itself; they answer different questions.
3. Decide Whether an Edit Should Reach the Original
A name is not a copy. Assigning a second name to an array gives both names the same object. A basic slice also shares the underlying numerical storage. An advanced selection gathers into independent storage. Use copy when independence is part of the task.
Inspect sharing before editing
shares_memory reports whether these arrays overlap in memory. A slice and an integer-index selection can show the same values while behaving differently when changed.
import numpy as np
a = np.array([10, 20, 30])
view = a[:2]
gathered = a[[0, 1]]
independent = a.copy()
print(np.shares_memory(a, view))
print(np.shares_memory(a, gathered))
view[0] = 11
gathered[1] = 99
print(a.tolist())
print(independent.tolist())True
False
[11, 20, 30]
[10, 20, 30]The slice changed the original first reading. The gathered array and explicit copy did not. np.asarray is useful for accepting an input as an array, but it may return an existing array unchanged; it is not a promise to make a copy.
4. Count Repeated Positions Deliberately
Repeated retrieval is straightforward, but repeated updates need care. When advanced indexing gathers a temporary array, an in-place-looking update can lose repeated contributions. If every occurrence should add to a count, NumPy's add.at performs an update at each supplied position.
Two alerts for the same greenhouse
Our saved alert IDs contain greenhouse one twice. We compare an indexed increment with accumulation that processes every occurrence.
import numpy as np
ids = np.array([1, 1, 2])
buffered = np.zeros(3, dtype=int)
buffered[ids] += 1
counts = np.zeros(3, dtype=int)
np.add.at(counts, ids, 1)
print(buffered.tolist())
print(counts.tolist())[0, 1, 1]
[0, 2, 1]The second result records all three alerts. This distinction will matter when later lessons accumulate repeated token IDs or category observations.
5. Choose Two Cells or a Rectangular Subtable
Botie asks for the first and last days from the first and last greenhouses. Do we want two particular cells, or every combination of those days and greenhouses? Both are sensible requests.
Two index arrays used together select pairs: first with first, last with last. To get the rectangular subtable, we can use np.ix_ to make the row and column selections independent. The example below shows both. NumPy accepts either expression, so we need to decide which request we mean before writing it.
Pairs and all combinations
Rows are three days; columns are three greenhouse readings.
import numpy as np
a = np.array([[10, 11, 12], [20, 21, 22], [30, 31, 32]])
print(a[[0, 2], [0, 2]].tolist())
print(a[np.ix_([0, 2], [0, 2])].tolist())[10, 32]
[[10, 12], [30, 32]]The first request returns two cells. The second returns four cells arranged as two rows and two columns.
Check yourself
Questions on Selecting Pairs and Rectangles
Question 1 of 1
Which request selects all four corner cells as a two-by-two table?
Use this setup.
a = [[10,11,12],[20,21,22],[30,31,32]] as a NumPy array. Row indices are [0,2] and column indices are [0,2].6. Repeated Destinations Need an Accumulation Rule
Later, several token positions may refer to the same embedding row. An update must add every contribution to that row. Ordinary advanced-index assignment can read a temporary array and write it back, so repeated positions do not behave like a sequence of additions.
np.add.at performs accumulation at repeated destinations. It is useful when the meaning is explicitly to collect contributions. It does not replace every indexed assignment: assigning a final value and accumulating several changes are different operations.
counts = np.zeros(3, dtype=int)
np.add.at(counts, [0, 0, 2], 1)
# counts: [2, 0, 1]Check yourself
Questions on Parts 1 to 6
Question 1 of 4
How many axes survive the slice?
Use this setup. The code is given; its result is for you to work out.
import numpy as np
a = np.array([[10,20,30],[14,22,36]])
selected = a[0:1]Try it with Botie
Build with Botie
Write and run Python