1. Introduction & Why NumPy
NumPy (Numerical Python) is the foundation of the entire Python scientific stack. Pandas, scikit-learn, TensorFlow, SciPy, and Matplotlib all sit on t
Purpose#
NumPy (Numerical Python) is the foundation of the entire Python scientific stack. Pandas, scikit-learn, TensorFlow, SciPy, and Matplotlib all sit on top of NumPy's core object: the ndarray (N-dimensional array).
Why NumPy exists — and why it's fast#
A Python list is an array of pointers to scattered PyObject boxes. Each integer is a full object with a type header, reference count, and value. Iterating a list means chasing pointers all over memory and doing dynamic type checks on every element.
A NumPy ndarray is a single contiguous block of raw memory holding values of one fixed type. This unlocks three speedups:
| Reason | Explanation |
|---|---|
| Contiguous memory | Values sit next to each other → CPU cache hits, no pointer chasing |
| Fixed dtype | No per-element type checking; the loop knows every item is e.g. float64 |
| Vectorization (C loops) | Operations run in compiled C, not the Python interpreter — often 10–100× faster |
import numpy as np
size = 1_000_000
py_list = list(range(size))
np_arr = np.arange(size)
# Python list: interpreted loop
%timeit [x * 2 for x in py_list] # ~60 ms
# NumPy: vectorized C loop
%timeit np_arr * 2 # ~1 ms
Expected output (approx.):
60.3 ms ± 2.1 ms per loop
1.02 ms ± 30 µs per loop
Memory layout & the ndarray#
An ndarray is described by a small header plus a pointer to a data buffer:
- data: the raw contiguous bytes
- dtype: how to interpret each element (e.g.
int64= 8 bytes) - shape: dimensions, e.g.
(3, 4) - strides: bytes to step to move one index along each axis
Array [[1,2,3],
[4,5,6]] with dtype int64 (8 bytes)
Memory (C order): 1 2 3 4 5 6 (row-major, rows stored consecutively)
strides = (24, 8) → move 24 bytes down a row, 8 bytes across a column
📌 Remember: The array header is tiny and cheap to copy. Reshaping or transposing usually just changes
shape/stridesand returns a view onto the same data buffer — no copying.
⭐ Interview Question: Why is NumPy faster than a Python list? Contiguous fixed-dtype memory (cache-friendly, no boxing), plus vectorized operations executed in compiled C rather than the Python interpreter.