NumPy for Machine Learning: 5 Essential Ideas

⚡ TL;DR: NumPy gives Python fast arrays. Almost all of machine learning is array arithmetic, so learning shapes, indexing and broadcasting is the fastest route from understanding the maths to writing the code.

You have the linear algebra. NumPy for machine learning is how you actually run it. Every ML library in Python — scikit-learn, PyTorch, TensorFlow — is built on NumPy arrays or something that behaves like them.

Why NumPy instead of Python lists

A Python list can hold anything, so every element carries type information and lives wherever memory allows. A NumPy array holds one type in one contiguous block, which lets operations run in compiled C rather than interpreted Python.

✅ The practical difference: multiplying a million numbers takes a Python loop roughly a second. The same operation on a NumPy array takes a few milliseconds. Train a model that does this thousands of times and the gap stops being an inconvenience and becomes the difference between possible and impossible.

Shape is the concept that matters

Every array has a shape — a tuple giving its size along each dimension. Most errors you will hit are shape errors, so it is worth building the habit of checking early and often.

ShapeDimensionsIn machine learning this is…
()0A scalar — a single loss value
(4,)1A vector — one row’s features
(100, 4)2A matrix — your whole dataset: 100 rows, 4 features
(32, 28, 28)3A batch of 32 greyscale images

The convention throughout machine learning is rows are samples, columns are features. A dataset of 100 houses with 4 measurements each has shape (100, 4) — never (4, 100).

Broadcasting: the idea worth understanding properly

Broadcasting is NumPy stretching a smaller array across a larger one so their shapes line up, without ever copying the data.

NumPy broadcasting diagram showing a 2 by 3 array added to a 3 element array to produce a 2 by 3 result
The (3,) array is applied to every row of the (2, 3) array. No loop, and no copy of the data.

This is not a curiosity — it is how feature scaling works. Subtracting a (4,) array of column means from a (100, 4) dataset subtracts the right mean from the right column, across all 100 rows, in one operation.

🧪 The broadcasting rule

Compare shapes from the right. Two dimensions are compatible if they are equal, or if one of them is 1. Missing dimensions on the left are treated as 1.

(100, 4) and (4,) → compare 4 with 4 ✓, then 100 with nothing ✓ → works
(100, 4) and (100,) → compare 4 with 100 ✗ → fails

That second case trips up nearly everyone. To subtract a value per row rather than per column, reshape to (100, 1) first.

The operations you will actually use

Creating
np.array() · np.zeros() · np.ones() · np.arange() · np.linspace() · np.random.default_rng()
Reshaping
.shape · .reshape() · .T for transpose · np.newaxis to add a dimension
Maths
@ or np.matmul for matrix multiply · np.dot · .mean() · .std() · .sum()

The one to internalise is axis. On a (100, 4) dataset, arr.mean(axis=0) gives 4 numbers — the mean of each column, which is what you want for scaling. arr.mean(axis=1) gives 100 numbers, the mean of each row, which is almost never what you want. The rule: axis is the dimension that disappears.

Vectorise instead of looping

⚠️ If you are writing a for-loop over an array, stop

Almost every loop over NumPy data has a vectorised equivalent that is shorter and hundreds of times faster. Instead of looping to square every element, write arr ** 2. Instead of looping to find values above a threshold, write arr[arr > 5].

Boolean indexing like that is worth learning early — it is how you filter rows, count matches, and replace outliers, all without a loop.

Two gotchas that cause real bugs

Views versus copies. Slicing an array gives you a view into the original, not a copy. Modify the slice and you modify the original. When you want independence, call .copy() explicitly.

Integer division truncates. An array created from whole numbers has an integer dtype, and dividing can silently discard the fractional part in some operations. If you are doing maths on data, make it float — np.array([1, 2, 3], dtype=float).

🔑 Key Takeaways

  • NumPy for machine learning is about arrays: one type, contiguous memory, compiled speed.
  • Rows are samples, columns are features — shape (n_samples, n_features).
  • Broadcasting compares shapes from the right; dimensions must match or be 1.
  • axis is the dimension that disappears — axis=0 gives per-column results.
  • Slices are views, not copies. Use .copy() when you need independence.

Further reading

The official NumPy absolute beginners guide is genuinely good and takes about an hour, and the broadcasting documentation works through more shape combinations than fit here.

Where to go next

Scroll to Top