NumPy Introduction
The array engine under pandas, sklearn and torch
NumPy's ndarray is a fast, homogeneous, n-dimensional array with vectorized math — the primitive everything from pandas to deep learning is built on.
What you will learn
- Create and inspect ndarrays
- Explain why array ops beat Python loops
- Relate ndarray to later tools (pandas, torch)
What is this?
NumPy provides the ndarray: a homogeneous, fixed-size, n-dimensional array whose operations are implemented in optimized C and can run over every element without Python-level looping. This 'vectorization' is why the scientific Python stack is fast, and it's the storage core pandas wraps into Series/DataFrames.
Why do you need it?
- Pure Python loops on 10M numbers take seconds; the ndarray does it in milliseconds.
- pandas columns ARE numpy arrays; pandas speed inherits numpy speed.
- Everything downstream (scikit-learn, TensorFlow/PyTorch) imports, converts or extends ndarrays.
- One `arr.mean()` replaces a hand-written loop, count, sum and divide.
Mental model
A professional kitchen blender vs chopping by hand
Vectorized numpy vs Python loops
The blender processes a whole batch at once with one mechanism; hand-chopping processes one piece at a time. Vectorized ops are the blender.
How it works
- The ndarray stores a homogeneous block of memory — every cell the same dtype, contiguously laid out.
- Operations dispatch to compiled C loops (and optionally SIMD) that iterate the block without Python overhead.
- Ufuncs (universal functions) like np.add, np.sqrt apply element-wise across the whole array.
- Broadcasting lets differently-shaped compatible arrays combine element-wise.
- This design scales to GPUs: torch/tensorflow mirror the same layout and semantics.
From Python list to fast ndarray.
Examples
Loops vs vectorization
import numpy as np, timearr = np.arange(10_000_000, dtype="float64") + 1t0 = time.perf_counter()total = (arr * 2).sum() # vectorizedt1 = time.perf_counter()s = 0for x in arr: s += x * 2 # python loopt2 = time.perf_counter()print(round(t1 - t0, 4), round(t2 - t1, 2)) # e.g. 0.008 vs 1.9The arithmetic happens once per element in C for the whole 10-million-wide array. The loop pays per-element Python overhead. The gap grows with size — the prime reason vectorization is non-negotiable.
In production
- A fraud pipeline scores 50M transactions against matrix weights in numpy before any Python abstraction touches them.
- Embedding similarity in production is a numpy (or torch) matrix multiply over precomputed vectors.
- Feature engineering libraries like featuretools and category encoders ship numpy kernels for the hot paths.
Best practices
- Prefer array operations over explicit Python loops everywhere in hot code.
- Choose the smallest dtype that fits (float32 vs float64 halves memory and speeds up).
- Use np.arange/np.linspace/np.zeros instead of building lists then converting.
Common mistakes
- Calling np.array() on a pure-Python structure per row inside a loop (rebuild cost each time).
- Ignoring dtype: float64 arrays are slower and heavier than float32 when precision allows.
- Copying with np.array(arr) instead of np.asarray when reuse is safe.
Debugging tips
- Print arr.dtype, arr.shape and arr.strides when behaviour looks wrong — they explain most mysteries.
- Check performance with arr.nbytes: cast dtype/VT down to shrink memory and speed ops.
- If results are unexpectedly rounded, inspect dtype, not the algorithm.
Interview checkpoint
Quick quiz
The ND in ndarray stands for:
pandas columns internally hold numpy arrays.