Which Direction Are We Adding?
A table can hold several greenhouses across several days. Adding across a row answers a different question from adding down a column. We need to keep that distinction when we ask an array to calculate.
10 sections · 5 questions · 2 coding challenges
The arrow keys move between sections too.
Keeping the Meaning of a Scientific Table
BOTIE
NumPy's documented reduction operations make the chosen axis explicit. Our two-day greenhouse table is an invented example of why that choice matters. We are using an established array convention, not attributing the invention of tables or averages to NumPy.
Which Average Did We Actually Ask For?
Botie now has two days of temperatures for three greenhouses. We could ask for the average temperature of each greenhouse, or the average across all greenhouses on each day. Both are reasonable questions, but they have different answers.
The entries alone cannot tell the computer which question we mean. We need to describe the table's layout and say which direction the calculation should combine.
Name both directions
Rows are days; columns are greenhouses. Keep these labels in view before reducing anything.
Monday
- 10
- 20
- 30
Tuesday
- 14
- 22
- 36
What we can now calculate
Swapping rows and columns puts one greenhouse's readings together. Each row average then keeps that greenhouse separate.
Explore the full example
Choose an example, then change a value. Follow the calculation below to see which result changes and why. These are small teaching examples; the construction later asks you to choose the operations yourself.
BOTIE
Result from these values
- 012
- 121
- 233
Follow the operations
1. Days by greenhouses
10 20 30 14 22 36 2. Swap rows and columns
10 14 20 22 30 36 3. Mean within each row
- 012
- 121
- 233
4. Result
- 012
- 121
- 233
All days receive equal weight, and every greenhouse has a reading on every day. Editing this example does not change the workshop tests.
1. Give Each Axis a Job
One list was enough for one morning. With several mornings, a flat list would make us remember where each day begins and ends. Instead, let's keep one list per day and put those lists inside another list. This is a nested list.
We can use this arrangement to create a two-dimensional NumPy array. Its first axis follows the days and its second follows the greenhouses. An axis is a direction in the organisation of an array.
North Middle South
Monday 10 20 30
Tuesday 14 22 36A scalar is one value. A one-dimensional array is a sequence of values. Our two-dimensional array is a table of values, which we can also interpret as a matrix. The number of axes is different from the number of entries.
Build the table one row at a time
The outer list contains two items, each of which is itself a list. The first lookup chooses Tuesday's list. The second lookup chooses the middle greenhouse within that list. NumPy accepts these equally long rows as a rectangular numerical array.
import numpy as np
days = [
[10, 20, 30],
[14, 22, 36],
]
print(days[1])
print(days[1][1])
temperatures = np.array(days, dtype=float)
print(temperatures.tolist())[14, 22, 36]
22
[[10.0, 20.0, 30.0], [14.0, 22.0, 36.0]]The double square brackets in the final output preserve the rows: this is a list containing lists. A Python nested list could have unequal row lengths, but those rows would not form the regular numerical table we need here.
Read the shape as a tuple of axis lengths
A tuple is an ordered collection whose entries cannot be replaced after it is created. Python commonly writes tuples with parentheses. NumPy reports an array's shape as a tuple: one length for each axis, in axis order.
The ndim attribute counts axes. The size attribute counts all entries. These describe different things, so let's print each one separately.
import numpy as np
temperatures = np.array([
[10, 20, 30],
[14, 22, 36],
])
shape = temperatures.shape
print(shape)
print(shape[0])
print(shape[1])
print(temperatures.ndim)
print(temperatures.size)(2, 3)
2
3
2
6There are two day rows, three greenhouse columns, two axes, and six temperatures. The shape tuple records the lengths; it contains none of the temperatures. We can index that tuple to read a length, but we cannot replace one of its entries as we could with a list.
Ask for one reading, one day, or one greenhouse
In a two-dimensional array, the comma inside square brackets separates the row selection from the column selection. A colon by itself means all positions along that axis. So we can choose one row and one column, all columns of a row, or all rows of a column.
import numpy as np
temperatures = np.array([
[10, 20, 30],
[14, 22, 36],
])
print(temperatures[1, 1])
print(temperatures[0, :].tolist())
print(temperatures[:, 1].tolist())22
[10, 20, 30]
[20, 22]The first result is Tuesday's middle greenhouse reading. The second is all of Monday. The third follows the middle greenhouse across both days. Selecting one row or one column this way leaves a one-dimensional array.
2. Remove the Direction We Combine
To find one mean per greenhouse, we need to combine the days while keeping the greenhouses separate. The days occupy axis zero, so that is the axis we reduce. A reduction combines several entries into a summary.
North: (10 + 14) / 2 = 12
Middle: (20 + 22) / 2 = 21
South: (30 + 36) / 2 = 33
Result shape: (3,)The day axis disappears because its readings have been combined. The remaining entries belong to the three greenhouses.
Keep one answer per greenhouse
The mean method calculates an average. Its axis argument says which direction to combine. The result's shape is a one-entry tuple. The trailing comma is how Python distinguishes a one-entry tuple from parentheses around a single number.
import numpy as np
temperatures = np.array([
[10, 20, 30],
[14, 22, 36],
])
per_greenhouse = temperatures.mean(axis=0)
print(per_greenhouse.tolist())
print(per_greenhouse.shape)[12.0, 21.0, 33.0]
(3,)The result has one axis of length three. It is not a table with three rows and an unspecified number of columns. It has no second axis.
3. Ask the Other Question
For one mean per day, we combine the greenhouse axis instead. Reducing axis one leaves the day axis. The same six temperatures now answer a different question.
Monday: (10 + 20 + 30) / 3 = 20
Tuesday: (14 + 22 + 36) / 3 = 24
Result shape: (2,)Neither summary is inherently better. The useful one depends on whether Botie needs a greenhouse comparison or a daily report.
Compare a daily summary with a single overall value
Providing axis one gives a result for each day. Leaving out axis asks mean to combine every entry into one scalar. That single number no longer keeps either day or greenhouse separate.
import numpy as np
temperatures = np.array([
[10, 20, 30],
[14, 22, 36],
])
per_day = temperatures.mean(axis=1)
print(per_day.tolist())
print(per_day.shape)
print(temperatures.mean())[20.0, 24.0]
(2,)
22.0The list has two daily means. The final number averages all six readings. Before writing a reduction, say what one answer should represent and how many answers you need.
4. Predict the Shape Before Running the Code
We now have a way to check whether an operation left us the right kind of result: inspect its shape. That check is useful before reading any particular number. The right shape does not prove the numbers are correct, but the wrong shape can reveal that we answered a different question.
There is one more detail to understand before editing a selected row. A NumPy slice can be a view, meaning it refers to part of the original array's storage. Giving that view a new variable name does not give it independent data.
If Botie wants to try a correction without altering the saved readings, we need a copy.
A view shares readings; a copy keeps its own
We select Monday's row twice. One selection remains a view. For the other, we call copy to give it its own numerical storage. Then we change the first entry of each selection.
import numpy as np
temperatures = np.array([
[10, 20, 30],
[14, 22, 36],
])
monday_view = temperatures[0, :]
monday_copy = temperatures[0, :].copy()
monday_view[0] = 11
monday_copy[0] = 99
print(temperatures[0, :].tolist())
print(monday_copy.tolist())[11, 20, 30]
[99, 20, 30]Changing the view changed Monday in the original table. Changing the copy did not. The workshop will summarise the readings, and the challenges will calculate both kinds of mean without modifying their inputs.
Check yourself
Questions on Parts 1 to 4
Question 1 of 5
Which axis must disappear to leave one mean per greenhouse?
Rows are Monday and Tuesday. Columns are north, middle, and south.
import numpy as np
temperatures = np.array([
[10, 20, 30],
[14, 22, 36],
])Try it with Botie
Build with Botie
Write and run Python