NumPy in 8 Slides
Theme
Palette
Download
Caption (tap to copy)
📖 Deep dive (full written explanation)
This fourth post is deliberately code-heavy. The previous posts built understanding; this one builds fluency. The aim is not to survey the entire NumPy API — that would be useless to memorize — but to drill the handful of patterns that cover the overwhelming majority of real work.
The strong recommendation is to type these snippets at a keyboard rather than skim them. NumPy fluency is muscle memory: creating arrays, slicing them, masking them, and reducing along axes until those moves become automatic. Reading about it gets you nowhere near the same place as running it.
These six creation patterns cover almost everything you will need to make arrays. np.array converts existing data. np.zeros and np.ones build arrays of a given shape filled with a constant — useful for preallocating. np.arange is like range but returns an array. np.linspace gives a fixed count of evenly spaced points, which arange cannot do cleanly. np.random.rand fills with random values.
The distinction worth remembering is arange versus linspace: arange takes a step size and the endpoint is excluded, while linspace takes a count and includes both endpoints. Reaching for the wrong one is a common minor bug.
Indexing and slicing on a 2D array follow a clear grammar: the first index is the row axis, the second is the column axis. a[0] grabs an entire row. a[:, 1] uses a colon to take all rows of column 1. a[1, 2] pulls a single scalar. a[0:2, 1:3] takes a rectangular sub-block.
The pattern to internalize is a[rows, cols], where each position can be a single index, a slice, or a colon for 'everything'. Remember from the previous post that these basic slices return views, so assigning into them modifies the original array.
Boolean masking is one of the most powerful patterns in NumPy. a > 5 does not return a single boolean — it returns a boolean array the same shape as a, with True wherever the condition holds. Indexing with that mask, a[mask], selects exactly the elements that are True, giving you a filtered array.
The last two lines show the in-place form: a[a < 5] = 0 finds every element below 5 and assigns 0 to all of them at once, no loop required. This combination of comparison-to-mask and mask-indexing replaces an enormous amount of conditional looping.
The axis argument is the single concept that confuses newcomers most, so it is worth slowing down. Reductions like sum, mean, max, and std take an axis that names which dimension to collapse. axis=0 collapses the row dimension, leaving one value per column. axis=1 collapses the column dimension, leaving one value per row. With no axis, the whole array reduces to one scalar.
The mental trick that sticks: the axis you name is the one that disappears. Name axis=0 and the rows vanish, leaving columns. Get this and half of NumPy aggregation stops being guesswork.
This snippet makes the axis rule concrete on a 2-by-3 array. a.sum() with no axis adds all six values to 21. a.sum(axis=0) collapses the two rows, summing each column to give [5,7,9]. a.sum(axis=1) collapses the three columns, summing each row to give [6,15]. a.mean(axis=0) does the same column-wise collapse with averaging.
The reliable habit is to predict the output shape before running: collapsing axis=0 of a (2,3) array leaves shape (3,), and collapsing axis=1 leaves (2,). If the shape you get is not the shape you predicted, you flipped the axis.
This comparison cements the axis concept side by side. On the left, axis=0 collapses rows and produces a per-column result — turning a (2,3) array into a length-3 vector, the natural choice for 'compute something for each feature'. On the right, axis=1 collapses columns and produces a per-row result — a length-2 vector here, the natural choice for 'compute something for each sample'.
The phrasing in quotes maps the abstract axis to real intent. In a dataset where rows are samples and columns are features, axis=0 summarizes features and axis=1 summarizes samples. Tying the number to that meaning is what makes it stick.
This snippet shows everyday broadcasting at work. prices is a length-3 array and tax is a length-3 array; multiplying prices by (1 + tax) applies the matching tax rate to each price element-wise in one expression. There is no loop and no index bookkeeping.
This is the bread-and-butter use of broadcasting: applying a per-element factor across a whole array. Combined with the column-and-row pattern from the previous post, broadcasting eliminates the vast majority of the manual loops people instinctively reach for.
This final example ties everything together in a real preprocessing task: standardizing the columns of a feature matrix so each has mean 0 and unit variance. X.mean(axis=0) computes a per-column mean — a length-2 vector. X.std(axis=0) does the same for standard deviation. Then (X - mu) / sd broadcasts both vectors across the rows, normalizing every column in a single expression.
This exact pattern appears constantly in machine learning, where features on different scales need standardizing before training. It combines axis-wise reduction and broadcasting — the two big ideas of this post — into one clean, loop-free line. The final mean-check confirms the columns are now centered near zero.
These patterns are the ones worth committing to memory: the creation functions for building arrays, a[:, i] for grabbing a column, a[mask] for filtering by condition, the axis convention where 0 is per-column and 1 is per-row, and the standardization one-liner that combines reduction with broadcasting.
If these five become reflexes, you will write NumPy without consulting documentation for most tasks. They are the working core that the larger API extends.
That is the hands-on tour. You now have the everyday moves: creating arrays several ways, slicing and masking, aggregating along the correct axis, and broadcasting arrays together for clean element-wise work.
The final post in this series turns to what goes wrong. NumPy's sharp edges — shared-memory views, integer overflow, flipped axes, dtype and NaN surprises — all produce silent wrong answers rather than crashes, and the next post is the field guide to spotting them.