NumPy
In one line: a fixed-size, homogeneously-typed n-dimensional array plus compiled elementwise math over it.
Version at time of writing: 2.5.x · import numpy as np · Python 3.12–3.14
The mental model
A NumPy array is one contiguous block of memory plus three pieces of metadata: a shape, a dtype, and strides (how many bytes to step to move one element along each axis). Everything NumPy does — reshaping, transposing, slicing, broadcasting — is either arithmetic on that metadata (free, no copy) or a compiled loop over the buffer (fast).
Once you hold that picture, the behaviours that feel arbitrary stop being arbitrary:
arr.Tis instant on a 10 GB array because it only swaps strides — Memory Layout and Stridesarr[1:5]shares memory witharrbutarr1,2,3does not — Views vs Copies- adding a
(3,1)array to a(1,4)array gives(3,4)without allocating either operand — Broadcasting - appending to an array is expensive, because "fixed-size" is not negotiable
Why bioinformatics cares
Nearly every quantitative bio object is a matrix: an expression matrix (genes × samples), a distance matrix, a position weight matrix, a coverage vector, a genotype matrix. NumPy is where those live, and a per-element Python loop over a 20,000 × 500 matrix is ~10 million interpreter round-trips versus one compiled pass.
Biopython returns NumPy arrays in several places (Bio.motifs PWMs, Bio.PDB atom coordinates, alignment substitution counts), and pandas is NumPy underneath. You cannot skip this layer.
Core notes
The object ndarray · NumPy dtypes · Array Creation
Getting data out Indexing and Slicing · Boolean Masking · Fancy Indexing · Views vs Copies
Doing math Broadcasting · ufuncs · Vectorization · Axes and Reductions
Changing shape Reshaping and Stacking · Memory Layout and Strides
Specialised Structured Arrays · NumPy Random Generator · Linear Algebra with NumPy · Missing Data in NumPy · NumPy File IO
Applied
Applied - Expression Matrices with NumPy · Applied - Sequence Composition Analysis · Applied - Multiple Sequence Alignment Analysis
Install and check
pip install "numpy>=2.4,<3"
python -c "import numpy as np; print(np.__version__); np.show_config()"
np.show_config() tells you which BLAS you are linked against — relevant if matrix multiplication is unexpectedly slow.
The 20% that gets 80% of the work done
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6]]) # shape (2, 3)
a.shape, a.dtype, a.ndim, a.size
a.mean(axis=0) # column means → shape (3,)
a.sum(axis=1) # row sums → shape (2,)
a[a > 3] # boolean mask → 1-D
a[:, None] # add an axis → shape (2, 3, 1)... see broadcasting
np.where(a > 3, a, 0) # vectorised if/else
np.log2(a + 1) # ufunc, elementwise
a @ a.T # matrix multiply
What NumPy is not for
- Labelled data → Pandas
- Ragged / variable-length rows → lists, or an awkward-array style library
- Mostly-zero matrices →
scipy.sparse(single-cell count matrices are >90% zero; a dense NumPy array will exhaust your RAM) - Data larger than memory → Dask, Zarr, or chunked reading
Gotchas that bite newcomers
- Integer arrays overflow silently.
np.int8(127) + 1 == -128. Read counts inint32can overflow on large studies. arr == np.nanis alwaysFalse. Usenp.isnan. See Missing Data in NumPy.- Modifying a slice modifies the original. See Views vs Copies.
- Floating-point equality: use
np.isclose/np.allclose, never==. - NumPy 2 changed scalar promotion (NEP 50) —
np.float32(1) + 1.0staysfloat32now. See Versions and Compatibility.
See also
Pandas · Ecosystem Map · Learning Path