Data ScienceBeginner

NumPy Array Operations in Python

Learn NumPy basics in Python! A fun and easy guide to super-fast arrays, matrices, and data science math without using slow for-loops.

Try it yourself

Run this code directly in your browser. Click "Open in full editor" to experiment further.

Loading...

Click Run to see output

Or press Ctrl + Enter

How it works

Welcome to NumPy (Numerical Python) โ€” the bedrock under every serious piece of scientific Python. Pandas, SciPy, scikit-learn, Matplotlib, OpenCV, PyTorch, TensorFlow, JAX โ€” they all either are NumPy under the hood or speak its array protocol. If you want to do data science, ML, or image processing in Python, learning numpy basics is non-negotiable.

Why do we need NumPy at all when Python has lists? Because Python lists are generic containers โ€” they can hold mixed types, which forces Python to store every element as a full object with type info, refcounts, and pointer indirection. Multiplying a million-element list by 2 means a million method dispatches. NumPy throws all that overhead in the bin. ๐Ÿš€

ndarray: The Core Object

The numpy ndarray is a homogeneous, contiguous, n-dimensional block of memory. Three words doing a lot of work:

  • Homogeneous โ€” every element shares the same dtype (e.g. int64, float32, bool). No mixed types.
  • Contiguous โ€” the values sit next to each other in RAM, like a single packed buffer.
  • N-dimensional โ€” a 1D vector, a 2D matrix, a 3D image stack, a 4D batch of images โ€” same object, different shape.
  • Every ndarray has three attributes you'll use constantly:

    AttributeWhat it means
    shapeTuple of sizes per axis, e.g. (3, 4) is 3 rows ร— 4 cols
    dtypeElement type, e.g. float64, int32, uint8
    stridesByte step to move one slot along each axis (this is how views work without copying)

    Why NumPy is 10-100x Faster Than Python Lists

    Vectorization python is the term, and it stacks four things:

    1. C-implemented loops โ€” the inner loop is compiled C, not bytecode.

    2. Contiguous memory โ€” the CPU prefetcher loves linear access.

    3. SIMD via BLAS/OpenBLAS/MKL โ€” matrix ops dispatch to AVX/NEON.

    4. No per-element type checks โ€” dtype is known once.

    A quick benchmark you can run yourself:

    import numpy as np, time
    n = 10_000_000
    lst = list(range(n))
    arr = np.arange(n)
    
    t = time.time(); s = sum(x*x for x in lst); print("list:", time.time()-t)
    t = time.time(); s = (arr*arr).sum();      print("numpy:", time.time()-t)

    Expect a 50โ€“100ร— speedup. The gap widens with float math and matrix products.

    Creating Arrays

    np.array([1, 2, 3])        # from a list
    np.zeros((3, 4))           # 3x4 of 0.0
    np.ones((2, 2), dtype=int) # 2x2 of 1
    np.arange(0, 10, 2)        # [0 2 4 6 8]
    np.linspace(0, 1, 5)       # 5 evenly spaced points incl. endpoints
    np.random.default_rng().standard_normal((3, 3))  # modern Generator API
    np.eye(4)                  # 4x4 identity matrix
    np.full((2, 3), 7)         # constant fill
    Tip: Prefer np.random.default_rng() over legacy np.random.rand/randn โ€” it's the recommended API in NumPy 2.x.

    Indexing & Slicing

    a = np.arange(12).reshape(3, 4)
    
    a[0, 2]         # element at row 0, col 2
    a[1]            # entire row 1 (1D view)
    a[:, 1]         # entire column 1
    a[1:, :2]       # rows 1+, first two columns
    a[[0, 2], :]    # fancy indexing: rows 0 and 2
    a[a > 5]        # boolean mask: all elements > 5

    Critical rule: basic slicing returns a view on the same memory โ€” modifying a[1:] modifies a. Fancy indexing (integer arrays, boolean masks) returns a copy. If you need an independent buffer, call .copy().

    Broadcasting: The Magic Rule

    NumPy broadcasting is how arrays of different shapes combine without explicit loops. The rules:

    1. If arrays differ in ndim, pad the smaller shape with 1s on the left.

    2. Along each axis, sizes must be equal or one of them must be 1.

    3. The size-1 axis is virtually stretched to match the other.

    A = np.ones((3, 4))      # shape (3, 4)
    row = np.array([1,2,3,4])# shape (4,) -> treated as (1, 4)
    A + row                  # row stretched down all 3 rows
    
    col = np.array([[10],[20],[30]])  # shape (3, 1)
    A + col                  # col stretched across all 4 cols

    Mismatched shapes like (3,4) + (3,) fail โ€” use [:, None] to add an axis explicitly.

    Common Pitfalls

    1. List vs array confusion โ€” [1,2,3] * 3 gives [1,2,3,1,2,3,1,2,3]. np.array([1,2,3]) * 3 gives [3,6,9]. Different worlds.

    2. View vs copy surprises โ€” b = a[::2]; b[0] = 99 mutates a. Use a[::2].copy() when in doubt.

    3. Integer overflow โ€” np.array([200], dtype=np.uint8) + 100 silently wraps to 44. NumPy 2.x raises on out-of-range scalars (np.int8(1) + 1000) but arrays still wrap.

    4. Broadcasting mismatches โ€” always print(x.shape, y.shape) when you get ValueError: operands could not be broadcast together.

    5. Axis confusion โ€” axis=0 collapses rows (computes per column); axis=1 collapses columns (per row). The axis disappears.

    6. `.shape` vs `len()` โ€” len(a) only returns the size of the first axis. Use a.shape or a.size for the full picture.

    7. Equality โ€” a == b returns a boolean array, not a single bool. Use np.array_equal(a, b) or np.allclose(a, b) for floats.

    NumPy vs Pure Python vs Pandas vs Cupy/JAX

    ToolPick when
    Pure Python listFew items, mixed types, no math
    NumPyNumeric arrays, math, image/audio buffers
    PandasTabular data with named columns, time series
    CuPySame NumPy API, on NVIDIA GPU
    JAXNumPy API + autograd + JIT
    PyTorchDeep learning with autograd

    The numpy vs python list question answers itself: if it's numeric and bigger than a few hundred elements, use NumPy.

    Real-World Uses

  • Image processing โ€” a colour image is a (H, W, 3) uint8 array. OpenCV, Pillow, scikit-image all hand you NumPy arrays.
  • Audio DSP โ€” waveforms are 1D float32 arrays; FFTs and filters are pure NumPy/SciPy.
  • ML feature matrices โ€” X of shape (n_samples, n_features) is the scikit-learn interface.
  • Simulation grids โ€” fluid dynamics, cellular automata, weather models live on n-dim arrays.
  • Financial Monte Carlo โ€” vectorised random paths price options orders of magnitude faster.
  • Gradient descent backbones โ€” every deep learning library is an ndarray library with autograd bolted on.
  • Frequently Asked Questions

    Why is NumPy faster than a list?

    Homogeneous dtype + contiguous memory + compiled C loops + SIMD via BLAS. You skip the interpreter for the hot loop entirely.

    What's the difference between `np.array` and `np.asarray`?

    np.array always copies by default. np.asarray returns the input unchanged if it's already an ndarray of the right dtype โ€” use it in library code to avoid copies.

    Why does my slice modify the original?

    Basic slicing returns a view sharing memory. Add .copy() to detach it.

    What's the right dtype to use?

    float64 for general math, float32 for ML/GPU to halve memory, int64 for indices, uint8 for images, bool for masks. Mind promotion rules (NEP 50, adopted in NumPy 2.0).

    Should I learn NumPy or Pandas first?

    NumPy first. Pandas is built on NumPy, and every Pandas Series/DataFrame has an underlying ndarray you'll need to reach for eventually.

    What about JAX or PyTorch โ€” are arrays the same?

    Conceptually yes โ€” both mirror the NumPy API. JAX is closest (drop-in jax.numpy); PyTorch tensors differ slightly (.view vs .reshape) but the mental model transfers. Master NumPy first; the rest is dialect.

    Related examples