Summarise a Report Without Losing the Question
Botie needs totals, typical readings, and the greenhouse that needs attention first. A value, a position, and an ordered report answer different questions, even when they come from the same array.
10 sections · 4 questions · 2 coding challenges
The arrow keys move between sections too.
Turning a Large Report Into a Specific Answer
BOTIE
NumPy's statistical reductions accept axes, while functions such as argmax return positions instead of measurements. Keeping that distinction explicit lets a numerical summary remain connected to its original observation.
Sources for this history
Do We Need the Hottest Reading or the Greenhouse That Produced It?
A maximum temperature tells Botie how hot a greenhouse became. It does not by itself identify which greenhouse to inspect. An average answers another question, and an average alone can hide a large spread.
We will calculate these summaries with NumPy, keep their axis meanings explicit, and use returned positions to preserve the connection between values and labels.
Keep labels beside readings
The order is north, middle, south, annex.
Temperature
- 20
- 27
- 25
- 18
What we can now calculate
One ordering is computed from measurements and applied to their labels. Stable ties keep the earlier report order.
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
- 0annex
- 1north
- 2south
- 3middle
Follow the operations
1. Greenhouse names
- 0north
- 1middle
- 2south
- 3annex
2. Temperature in the same order
- 020
- 127
- 225
- 318
3. Rank from smallest
- 03
- 10
- 22
- 31
4. Gather selected entries
- 0annex
- 1north
- 2south
- 3middle
5. Result
- 0annex
- 1north
- 2south
- 3middle
Ordering is not a measure of danger. These temperatures only illustrate preserving aligned records. Editing this example does not change the workshop tests.
1. Choose the Summary and the Axis
sum adds values; mean shares their total across the entries; min and max keep an extreme value. Each can reduce a selected axis. The keepdims argument retains a length-one version of the reduced axis, which makes the result easier to align with the original table.
Subtract each day's own average
We preserve the greenhouse axis as length one in the daily mean. Broadcasting can then subtract each day's reference from its whole row.
import numpy as np
days = np.array([[10.,20.,30.],[14.,22.,36.]])
daily_mean = days.mean(axis=1, keepdims=True)
print(days.sum(axis=0).tolist())
print(daily_mean.tolist())
print((days - daily_mean).tolist())[24.0, 42.0, 66.0]
[[20.0], [24.0]]
[[-10.0, 0.0, 10.0], [-10.0, -2.0, 12.0]]Keeping the axis does not change the average. It records where that average belongs when we reuse it.
2. Describe the Centre and the Spread
A mean describes a centre; variance and standard deviation describe spread around it. NumPy's default variance divides squared deviations by the number of entries. Setting ddof to one instead uses one fewer in the divisor, the usual sample-variance convention when estimating from a sample.
The median selects the middle of ordered observations, averaging the two middle values for an even count. Quantiles locate other fractions of the ordered data. Their interpolation rule matters for small samples; we use NumPy's default linear rule here.
Keep the convention beside the result
For these four readings, compare the population variance, sample variance, and middle half of the ordered values.
import numpy as np
readings = np.array([18.,20.,25.,27.])
print(readings.mean())
print(np.median(readings))
print(readings.var())
print(np.round(readings.var(ddof=1), 4))
print(np.round(readings.std(), 4))
print(np.quantile(readings, [0.25, 0.75]).tolist())22.5
22.5
13.25
17.6667
3.6401
[19.5, 25.5]The two variance results use different denominators on the same observations. Choose the convention for the question, rather than changing ddof until a desired number appears. Standard deviation returns to the original temperature units.
3. Retrieve the Observation Behind an Extreme
max returns the largest value. argmax returns its position. If values tie, argmax returns the first occurrence along the chosen axis. The position can retrieve a greenhouse name or a complete record.
argsort returns all positions in sorted order. Apply that same order to every aligned array. np.sort returns sorted values instead; the array's sort method sorts that array in place.
Move names and readings together
We request a stable sort so ties keep their original order. These readings are distinct, but making the rule explicit prevents ambiguity later.
import numpy as np
names = np.array(["north","middle","south","annex"])
readings = np.array([20,27,25,18])
print(readings.max())
print(readings.argmax())
print(names[readings.argmax()])
order = np.argsort(readings, kind="stable")
print(names[order].tolist())
print(readings[order].tolist())27
1
middle
['annex', 'north', 'south', 'middle']
[18, 20, 25, 27]The index array carries the ordering rule to both collections. Sorting each collection independently would destroy the measurement-to-name relationship.
4. Count Decisions and Repeated Values
A Boolean comparison can be summarised too. count_nonzero counts true entries, any asks whether at least one is true, and all asks whether every entry is true. Use those operations to reduce an array of decisions to one answer.
unique can return distinct values together with their counts. Its usual sorted result differs from preserving the first occurrence order. Later, category IDs must use a vocabulary whose ordering we deliberately maintain.
How many alerts, and which values repeated?
The alert comparison includes the boundary. Tuple unpacking gives the two returned arrays separate names: values and counts.
import numpy as np
readings = np.array([20,27,27,18])
alerts = readings >= 25
print(np.count_nonzero(alerts))
print(alerts.any())
print(alerts.all())
values, counts = np.unique(readings, return_counts=True)
print(values.tolist())
print(counts.tolist())2
True
False
[18, 20, 27]
[1, 1, 2]There are two alert observations, even though both have the same value. Counting distinct alert temperatures would answer a different question.
Check yourself
Questions on Parts 1 to 4
Question 1 of 4
Which value identifies the hottest greenhouse's position?
Use this setup. The code is given; its result is for you to work out.
import numpy as np
readings = np.array([20,27,25,18])Try it with Botie
Build with Botie
Write and run Python