Preparing the Arrays We Need
Botie needs a place for tomorrow's readings and a set of times at which to collect them. We can describe those arrangements directly instead of typing every repeated value ourselves.
12 sections · 4 questions · 2 coding challenges
The arrow keys move between sections too.
When the Layout Was Known Before the Measurements
BOTIE
NumPy's array-creation routines make those intentions explicit. A shape describes the arrangement; a fill value or spacing rule describes its initial contents. Our greenhouse schedule is an invented example of that distinction.
Sources for this history
Do We Have to Type Every Entry?
Suppose Botie plans to check three greenhouses on two mornings. We know how many entries the report will need before we know the temperatures. We also want a regular schedule of checks. Neither task should require copying the same number over and over.
NumPy can create arrays from a shape, a repeated value, or a sequence rule. The choice matters: an empty place in a report is not evidence that the thermometer measured zero.
These small check sheets stand in for a larger greenhouse report.
Step 1 of 3
Decide what a row means
Each row belongs to a morning and each column to a greenhouse.
| Day | Column 0 | Column 1 | Column 2 |
|---|---|---|---|
| Monday | north | middle | south |
| Tuesday | north | middle | south |
Monday
- Column 0
- north
- Column 1
- middle
- Column 2
- south
Tuesday
- Column 0
- north
- Column 1
- middle
- Column 2
- south
Step 2 of 3
Choose the initial meaning
Zero is appropriate for a count of checks made so far. It is not a replacement for an unmeasured temperature.
| Greenhouse | Checks so far |
|---|---|
| North | 0 |
| Middle | 0 |
| South | 0 |
North
- Checks so far
- 0
Middle
- Checks so far
- 0
South
- Checks so far
- 0
Step 3 of 3
Generate the schedule
A start, stop, and spacing rule determine which times Botie will inspect.
Hour
- Reading 16
- Reading 28
- Reading 310
- Reading 412
Shape is part of the data we are preparing
The shape comes from the requested report. The filled sheet supplies references, while subtraction compares them with actual observations.
Prepare the target sheet before comparing readings
Botie needs a reference at every position in the report. Change the requested arrangement or target and check whether the prepared array still matches the observations it will be compared with.
BOTIE
Differences from the prepared targets
| 8 | 2 | -4 |
| 6 | -2 | -16 |
Follow the operations
1. Number of days
2
2. Number of greenhouses
3
3. Target temperature
20
4. Fill a rectangular sheet
20 20 20 20 20 20 5. Recorded temperatures
12 18 24 14 22 36 6. Subtract
8 2 -4 6 -2 -16 7. Result
8 2 -4 6 -2 -16
The workshop uses small positive dimensions. It does not expose uninitialised storage.
1. Start With a Shape and a Meaning
For a report with two mornings and three greenhouses, we need two rows and three columns. The shape is a tuple, passed as one argument. zeros fills an array with zeros; ones fills it with ones; full uses a value we supply.
A zero-filled array is useful for a counter before any events have occurred. A constant target table is useful for a shared rule. Neither is a table of observations merely because it has the right shape.
Create counts and targets separately
We specify integer storage for counts and floating-point storage for temperatures. The zeros and full functions allocate new arrays.
import numpy as np
checks = np.zeros((2, 3), dtype=int)
targets = np.full((2, 3), 20.0)
print(checks.tolist())
print(targets.tolist())
print(np.ones(3, dtype=int).tolist())[[0, 0, 0], [0, 0, 0]]
[[20.0, 20.0, 20.0], [20.0, 20.0, 20.0]]
[1, 1, 1]The arrays have deliberate initial values. NumPy also offers empty, which leaves numerical contents uninitialised. Those contents must be written before reading them; empty does not mean a safe table of zeros.
2. Reuse a Layout Without Guessing Its Size
Suppose the number of greenhouses changes. Hard-coding three columns in every calculation invites mistakes. The functions ending in _like can take their shape from an existing array. Their default dtype also follows that array, so override it when the new meaning needs a different type.
Make a counter that matches the incoming report
Here zeros_like gives each observed position a corresponding counter, and full_like creates a target table with the same layout.
import numpy as np
readings = np.array([[12., 18., 24.], [14., 22., 36.]])
counts = np.zeros_like(readings, dtype=int)
targets = np.full_like(readings, 20.0)
print(counts.shape)
print(counts.tolist())
print(targets.tolist())(2, 3)
[[0, 0, 0], [0, 0, 0]]
[[20.0, 20.0, 20.0], [20.0, 20.0, 20.0]]The layout now follows the data. ones_like provides the corresponding all-ones array when every position starts with one contribution.
3. Choose a Step or Choose a Count
A schedule may specify a time interval, while a graph may specify how many points to draw between two limits. Those are different requests. arange uses a step and excludes the stopping boundary. linspace uses a count and includes both endpoints by default.
For fractional spacings, linspace is often clearer when the intended count matters. Floating-point steps in arange can make boundary behaviour surprising.
Make an inspection schedule and a trial grid
The first call starts at six, stops before fourteen, and advances by two. The second requests five equally spaced trial settings including zero and one.
import numpy as np
hours = np.arange(6, 14, 2)
settings = np.linspace(0, 1, 5)
print(hours.tolist())
print(settings.tolist())[6, 8, 10, 12]
[0.0, 0.25, 0.5, 0.75, 1.0]The final argument has a different meaning in these two functions. Treating the count in linspace as a step would give the wrong experiment.
4. Preserve a Measurement When No Change Is Intended
Later we will use matrices to combine measurements. We also need a matrix that expresses leaving each measurement alone. An identity matrix has ones on its diagonal and zeros elsewhere, so each output keeps its matching input and ignores the others.
Create the identity pattern
eye creates this pattern. With three inputs, we request a three-by-three matrix. The matrix-calculation lesson will show how it acts on readings.
import numpy as np
identity = np.eye(3, dtype=int)
print(identity.tolist())
print(identity.shape)[[1, 0, 0], [0, 1, 0], [0, 0, 1]]
(3, 3)This is a rule we constructed, not a matrix fitted from data. Keep that distinction when using initial arrays in later model exercises.
5. Unfilled Storage Is Not a Measurement
Botie reserves a table before receiving tomorrow's readings. zeros supplies a known value, but zero could be mistaken for an actual measurement. full can fill the table with NaN to mark that it has not been measured yet. That choice requires a floating-point dtype.
empty has a different purpose: it allocates storage without initialising the values. Use it only when every position will be written before being read. Whatever numbers happen to appear there are not random samples and must never enter an average as observations.
6. Build Coordinates and Measurements Separately
Botie plans to place thermometers along a bed. Before any thermometer reports, we already know where its reading will belong. We can store the positions in one array and reserve a second array for the measurements.
If we know the endpoints and how many positions we want, linspace gives us that arrangement. If we know the step between positions, arange may be more convenient, though floating-point steps need care near the endpoint. For a fixed sampling schedule, we can also start with integer indices and convert them to times or positions.
Reserve three thermometer positions
Botie places thermometers at both ends and the centre of a four-metre bed.
import numpy as np
positions = np.linspace(0, 4, 3)
temperature = np.full(positions.shape, np.nan)
temperature[1] = 21.5
print(positions.tolist())
print(np.isfinite(temperature).tolist())[0.0, 2.0, 4.0]
[False, True, False]Only the centre has reported. The coordinate at zero metres is legitimate; a zero temperature would not mean unmeasured.
Check yourself
Questions on Parts 1 to 6
Question 1 of 4
What shape does this allocation request?
Use this setup. The code is given; its result is for you to work out.
import numpy as np
counts = np.zeros((2, 3), dtype=int)Try it with Botie
Build with Botie
Write and run Python