Plotting and notebooks
Use array shapes, broadcasting and reductions to express a small data transformation.
THE IDEA
A plot is a claim about two quantities
A plot turns arrays into shapes you can see, but the shape means nothing until you say what each axis measures and in what unit. The recipe is always the same: compute the x values and the y values as arrays of equal length, then draw one against the other. The usual Python library for this is matplotlib. It is large, so here we only compute the arrays in NumPy and draw them with a small plot component of our own. The thinking is identical.
plt.plot(w, loss)
plt.xlabel("candidate weight w")
plt.ylabel("mean squared error (loss)")The same 41 points. A curve with a dip, but you cannot say what is on either axis, so you cannot use it.
Notebooks: the screen shows an order, the kernel remembers another
A notebook is a list of cells that you can run in any order, any number of times. The program state lives in a separate kernel (a running Python process), not in the page. Each cell shows a counter like In [3]: the order in which cells actually ran. Editing a cell changes the page, not the kernel, until you run it.
That gap produces hidden state bugs. Step through a small one:
A fresh kernel. Nothing has run, so the kernel has no variables.
scores = np.array([0.2, 0.5, 0.7, 0.9, 0.4]) # cell 1threshold = 0.6 # cell 2flagged = scores > threshold # cell 3print(flagged.sum()) # cell 4A clean run would print 2. Some cells have not run yet.
Predict first. You change threshold = 0.6 to 0.8 in cell 2 but only re-run cell 4 (the count). What does it print?
The common mistake and the habit that prevents it
A notebook that works only because of what you ran earlier cannot be reproduced by anyone else, including you tomorrow. Before you trust a result or share a notebook, use restart the kernel and run all cells in order. If it fails or changes the answer, the notebook had hidden state.
Chapter context
A tensor is a multidimensional array with a shape and element type. Many AI bugs come from doing a valid operation along the wrong axis. Write the intended dimensions before trying to shorten the code.
TRY IT YOURSELF
Part 1. Repair a notebook with hidden state
This simulated notebook looks correct only because the kernel still remembers an older run. Complete the tasks; they tick from the real state of the simulation.
- To do: Press Restart and run all on the notebook as it stands, and read the error
- To do: Reorder the cells so that Restart and run all finishes with no error
- To do: Change the threshold to 0.8 in its cell. The notebook should now warn that an output is stale
- To do: Make every output match a clean run again: with threshold 0.8 the printed answer must be 1
scores = np.array([0.2, 0.5, 0.7, 0.9, 0.4]) # cell 1 flagged = scores > threshold # cell 2 print(flagged.sum()) # cell 3 threshold = # cell 4 This order cannot survive a restart: NameError: name 'threshold' is not defined
Part 2. Compute a curve and plot it
- A one-weight model predicts w * t. The true relationship is y = 2 * t. Compute the mean squared error for 41 candidate weights from 0 to 4 and plot the loss curve.
- w is np.linspace(0, 4, 41). loss has one number per candidate weight: use broadcasting, w[:, None] * t[None, :] has shape (41, 3).
- best_w is the candidate with the lowest loss. Give the plot an x label and a y label that say what the numbers are. show(...) draws the curve below the editor.
Stuck, or something not working? You can come back to it any time.
CHECK YOUR UNDERSTANDING
What does a stale notebook variable threaten?
Chapter reference: math, worked example & code
This section belongs to the whole chapter, so it is the same on every lesson in it and may cover a different lesson's topic. The code for the experiment you just ran is inside the experiment itself.
Math and notation
For a data matrix , feature means are
Here i indexes examples and j indexes features. The mean vector has d entries, so subtracting it from X broadcasts along rows.
Worked example
For X = [[1, 2], [3, 4]], the feature means are [2, 3]. Centering produces [[-1, -1], [1, 1]]. Each centered column has mean zero. Computing row means instead would answer a different question even though the operation is valid.
Reference code
The following example uses the Python standard library and does not call a remote service.
X = [[1, 2], [3, 4]]
means = [sum(row[j] for row in X) / len(X) for j in range(2)]
centered = [[x - m for x, m in zip(row, means)] for row in X]
assert means == [2, 3]
assert centered == [[-1, -1], [1, 1]]
Python examples are provided for study and local execution; this page does not execute Python.
Common mistakes
Broadcasting is a shape rule, not permission to ignore axis meanings. Vectorized code can create large intermediate arrays. Normalize training and test data with training statistics only.