Giving Measurements a Place
Three thermometers give us three readings. Before we can calculate with them, we need to decide how those readings are stored, which position belongs to which thermometer, and what an operation should do to the collection.
10 sections · 5 questions · 2 coding challenges
The arrow keys move between sections too.
When One Calculation Needed to Work on Many Measurements
BOTIE
The NumPy authors' 2020 account describes an array model that combines compact expressions with compiled numerical operations. The useful idea for us is simple: organise the readings once, then express a calculation for the collection. Our greenhouse readings are invented, not measurements from that paper.
How Do We Give the Computer Our Measurements?
Suppose Botie checks three greenhouses each morning. Today the thermometers read 12, 18, and 24 degrees Celsius. We can write those readings on paper, but a program needs them in a form it can work with.
Let's start with one reading, then work out how to keep all three together. Python gives us several ways to organise information. We will see why a list is useful for keeping entries in order, a dictionary is useful for finding a named reading, and a NumPy array is useful for calculating with the readings.
Give every greenhouse a position
Keep the same greenhouse order throughout the calculation. A result in the first position still belongs to the first greenhouse.
Greenhouse
- North
- Middle
- South
Celsius
- 12
- 18
- 24
What we can now calculate
Each wire still carries one entry per greenhouse. The multiplication changes the degree size; the addition changes the reference point.
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
- 053.6
- 164.4
- 275.2
Follow the operations
1. Greenhouse readings in Celsius
- 012
- 118
- 224
2. Set a constant
1.8
3. Multiply
- 021.6
- 132.4
- 243.2
4. Set a constant
32
5. Add
- 053.6
- 164.4
- 275.2
6. Result
- 053.6
- 164.4
- 275.2
This is a unit conversion, not a fitted prediction rule. Editing this example does not change the workshop tests.
1. A Value, a Name, and a Collection
Suppose we only had one thermometer. We could keep its reading under one name and use that name whenever we needed the temperature. Now suppose Botie has a hundred thermometers. Giving every reading its own variable would make even a simple calculation tedious. We need a way to keep related readings together.
A data structure is a way of organising information so that we can find it and work with it. Python gives us several choices. We will start with a list, which keeps items in a sequence. The position of an item is called its index.
Position: 0 1 2
Greenhouse: North Middle South
Celsius: 12 18 24Positions start at zero. Position zero identifies the first reading; it does not mean that the temperature is zero. We have decided that the first position belongs to the north greenhouse.
Start with one reading, then keep three together
The equals sign assigns a value to a name. Here, north refers to one number, which we call a scalar. Square brackets with comma-separated items create a list. Putting square brackets after the list's name retrieves an item instead.
The print function displays what we give it. The len function tells us how many items the list contains. Parentheses hold the information passed to a function.
north = 12
readings = [north, 18, 24]
print(north)
print(readings)
print(readings[0])
print(len(readings))12
[12, 18, 24]
12
3The first line is one number. The second is our collection. The third retrieves the north greenhouse's reading, and the fourth counts the entries. A list can contain other kinds of values too, but this one contains only temperatures.
Correct one entry without replacing the whole report
Suppose the middle thermometer was misread, and Botie also checks a fourth greenhouse. A list is mutable: we can change its contents after creating it. Assigning to an index replaces that item. Calling append adds an item at the end. An operation attached to an object with a dot, such as append, is called a method.
A slice retrieves a range of positions. The starting position is included and the stopping position is excluded. This example asks for positions one and two.
readings = [12, 18, 24]
readings[1] = 19
readings.append(21)
print(readings)
print(readings[1:3])[12, 19, 24, 21]
[19, 24]The corrected reading stays in the middle greenhouse's position. The fourth greenhouse goes at the end. Taking the slice does not remove entries from the original list. Each worked example on these pages starts with its own data, so this correction does not carry into the next example.
2. Apply the Rule One Reading at a Time
Before asking Python to calculate for a whole collection, let's work through one reading. Celsius and Fahrenheit use different sized degrees and different zero points. We first multiply by the scale between their degree sizes. Then we add the offset between their zero points.
North: (12 × 1.8) + 32 = 53.6
Middle: (18 × 1.8) + 32 = 64.4
South: (24 × 1.8) + 32 = 75.2These are three separate conversions. We are changing the units of each observation, so we still need one answer per greenhouse.
Give each step a name
In Python, the asterisk means multiplication. We can store the intermediate result under a name, then use it in the next instruction. This lets us inspect each step before applying the rule to all three readings.
celsius = 12
scaled = celsius * 1.8
fahrenheit = scaled + 32
print(scaled)
print(fahrenheit)21.6
53.6The scaled value is only an intermediate result. We must also shift the zero point before reporting Fahrenheit. Both variables here refer to single numbers, not lists.
3. Tell the Computer Which Kind of Number We Need
Our list keeps the readings together, but Python does not interpret every list operation as arithmetic on its entries. We need a numerical collection whose operations have that meaning. NumPy supplies one: the array, whose Python type is called ndarray.
For the ordinary numerical arrays in these lessons, every entry uses the same data type, or dtype. Integers store whole numbers. Floating-point numbers allow fractional readings, although many decimals are represented approximately. The data type describes how values are stored; it does not record their units.
We will explicitly request floating-point storage because temperatures and their conversions may contain fractions.
Turn the list into a numerical array
Importing NumPy makes its tools available. The name np is a short name we choose for it. The array function takes our Python list and creates an array. The named argument dtype tells it which kind of values to store.
The dtype attribute reports that choice. The tolist method returns an ordinary Python list, which gives us a convenient way to print the entries. It does not change the array into a list in place.
import numpy as np
readings = [12, 18, 24]
celsius = np.array(readings, dtype=float)
print(celsius.tolist())
print(celsius.dtype)[12.0, 18.0, 24.0]
float64The decimal points show the floating-point values in the returned list. The reported float64 is NumPy's 64-bit floating-point type used here. The three positions still belong to the same three greenhouses.
The same multiplication sign can do two different things
Let's multiply a list and an array by the same whole number. Before reading the output, consider what each collection is designed to do: the list supports repeating a sequence; the numerical array supports multiplying its entries.
import numpy as np
readings = [12, 18, 24]
celsius = np.array(readings)
print(readings * 2)
print((celsius * 2).tolist())[12, 18, 24, 12, 18, 24]
[24, 36, 48]Repeating the list gives six entries. Multiplying the array gives three doubled values. If we want to calculate a new temperature for each greenhouse, we need the second behaviour.
Convert the collection and prepare it for display
Now we can apply the two conversion steps to the array. NumPy performs the arithmetic for each entry. NumPy's round function takes the result and a number of decimal places. We keep that rounded result separately, then turn it into a list for printing.
import numpy as np
celsius = np.array([12, 18, 24], dtype=float)
scaled = celsius * 1.8
fahrenheit = scaled + 32
displayed = np.round(fahrenheit, 1)
print(displayed.tolist())
print(celsius.tolist())[53.6, 64.4, 75.2]
[12.0, 18.0, 24.0]We have one converted value per greenhouse. These arithmetic expressions produce new arrays, so the original Celsius readings are still available. Rounding is a display choice; it does not make floating-point arithmetic exact.
4. Check the Meaning as Well as the Numbers
A plausible number is not enough. We need the right units, the right order, and the right number of results. A familiar reference temperature helps us check the conversion.
Freezing point: (0 × 1.8) + 32 = 32
Boiling point at standard atmospheric pressure: (100 × 1.8) + 32 = 212There is another question our array cannot answer on its own: which entry belongs to which greenhouse? We must keep that information with the report.
Use a dictionary when the name is how we find the reading
A dictionary associates a key with a value. Here each key is a greenhouse name, written as a quoted string of text. Its value is the temperature. Curly braces contain the entries, and a colon separates each key from its value.
A list lookup uses a position. This dictionary lookup uses a name. When we later need a numerical array, we can first request the readings in an explicit order.
by_greenhouse = {
"north": 12,
"middle": 18,
"south": 24,
}
print(by_greenhouse["north"])
ordered_readings = [
by_greenhouse["north"],
by_greenhouse["middle"],
by_greenhouse["south"],
]
print(ordered_readings)12
[12, 18, 24]The dictionary is useful for looking up a named reading; the array is useful for numerical calculations across readings. Neither structure knows that these numbers are Celsius. That meaning still belongs in our variable names, labels, and explanation.
Check yourself
Questions on Parts 1 to 4
Question 1 of 5
What does position zero identify in our temperature array?
The greenhouse names and Celsius readings use the same order.
import numpy as np
greenhouses = ["north", "middle", "south"]
readings = np.array([12, 18, 24])Try it with Botie
Build with Botie
Write and run Python