Written and maintained by CASRAI Editorial Board
Last updated
numpy.std computes the standard deviation of an array. Called as np.std(a), it divides by N, so it returns the population standard deviation of the flattened array. For a sample standard deviation, pass ddof=1. That single default is the most common source of mismatched numbers between NumPy, pandas and a calculator, and it is the main thing this guide settles.
What np.std is used for in research
Standard deviation summarises how far values spread around their mean. In research code, np.std is typically used to report the spread of a measured variable, to standardise features (subtract the mean, divide by the standard deviation), and to turn replicate measurements into an error estimate. The function operates on any array-like input and can reduce along one axis or across the whole array.
Related reading on CASRAI: coefficient of variation (standard deviation relative to the mean), mean absolute deviation as an alternative spread measure, and Python for exploratory data analysis for the wider workflow.
Install or access
The NumPy project’s install page gives pip install numpy for pip and conda install numpy (inside an activated environment) for conda. To confirm the install, run:
import numpy as np
print(np.__version__)
Source: numpy.org/install, checked 2026-10-29.
Step-by-step: np.std with axis, ddof, dtype and where
The signature in the current NumPy manual (v2.5) is:
numpy.std(a, axis=None, dtype=None, out=None, ddof=0, keepdims=<no value>, *, where=<no value>, mean=<no value>, correction=<no value>)
- Whole array.
np.std(a). Withaxis=None(the default) the standard deviation is taken over the flattened array. Fora = np.array([[1, 2], [3, 4]])the result is1.1180339887498949. - Along an axis.
np.std(a, axis=0)gives one value per column,array([1., 1.]);np.std(a, axis=1)gives one value per row,array([0.5, 0.5]). - Sample instead of population.
np.std(a, ddof=1). The manual defines the divisor as N – ddof and states that ddof is zero by default. - Control precision.
np.std(a, dtype=np.float64). Integer input is computed in float64 by default; float input keeps the array’s own type. - Use only some elements. Pass a boolean mask with
where=(added in NumPy 1.20.0). Witha = np.array([[14, 8, 11, 10], [7, 9, 10, 11], [10, 15, 5, 10]]),np.std(a)is2.614064523559687andnp.std(a, where=[[True], [True], [False]])is2.0, because the third row is excluded.
Population vs sample: what ddof does
The manual describes ddof=0 as sometimes called the “population standard deviation” and ddof=1 as the “sample standard deviation”, using Bessel’s correction. It adds that the resulting estimate of the standard deviation is still biased, but less than it would have been without the correction.
A worked example you can reproduce: for x = np.array([2, 4, 4, 4, 5, 5, 7, 9]) the mean is 5 and the squared deviations sum to 32. np.std(x) divides by 8 and returns 2.0; np.std(x, ddof=1) divides by 7 and returns 2.138089935299395.
Which one to report
If the array is the entire population you care about, ddof=0 is the matching choice. If the array is a sample drawn to estimate the spread of a larger population, which is the usual situation in experimental work, use ddof=1 and say so in the methods text. Whichever you use, state it: a bare “SD” without the divisor is ambiguous.
The correction argument (NumPy 2.0 and later)
NumPy 2.0.0 added correction, the Array API name for ddof, and mean, which lets you pass a precomputed mean. Only one of ddof and correction may be given. np.std(x, correction=1) returns the same value as np.std(x, ddof=1).
Output and how to read it
The return value is a float (or an array of floats when you reduce along an axis), in the same units as your data. It is never negative. For complex input, NumPy takes the absolute value before squaring, so the result is real and nonnegative. Judge the number against the mean: a standard deviation of 2.0 means very different things around a mean of 5 and around a mean of 500, which is why the coefficient of variation is often reported alongside it.
Troubleshooting
NumPy and pandas give different answers
pandas defines DataFrame.std(*, axis=0, skipna=True, ddof=1, numeric_only=False, **kwargs) and normalises by N – 1 by default, so it returns a sample standard deviation where np.std returns a population one. The pandas documentation says that to match numpy.std you should use ddof=0 and skipna=False. Its own example, a DataFrame with age = [21, 25, 62, 43] and height = [1.61, 1.87, 1.49, 2.01], shows the gap:
| Call | age | height |
|---|---|---|
df.std() (ddof=1) |
18.786076 | 0.237417 |
df.std(ddof=0) |
16.269219 | 0.205609 |
The fix is to choose one convention and set ddof explicitly in both libraries.
The result is nan because of missing values
For an array with NaN values, use np.nanstd, which ignores NaNs; its divisor is N – ddof where N is the count of non-NaN values. For a = np.array([[1, np.nan], [3, 4]]), np.nanstd(a) returns 1.247219128924647, np.nanstd(a, axis=0) returns array([1., 0.]) and np.nanstd(a, axis=1) returns array([0., 0.5]). An all-NaN slice, or zero degrees of freedom, returns NaN with a RuntimeWarning.
float32 precision
The NumPy manual warns that the computed standard deviation can be inaccurate, especially for float32, and recommends dtype=np.float64. Its example fills a float32 array with half 1.0 and half 0.1: np.std(a) returns np.float32(0.45000005), while np.std(a, dtype=np.float64) returns 0.44999999925494177.
Division by zero or a warning with ddof=1
With ddof=1 a single-element slice has N – ddof equal to 0, so there is no valid estimate. Check that every slice you reduce over has more than ddof elements.
Free alternatives
| Tool | Function | Default divisor |
|---|---|---|
| NumPy | numpy.std |
N (ddof=0) |
| NumPy, ignoring NaN | numpy.nanstd |
N – ddof, N = non-NaN count; ddof=0 by default |
| pandas | DataFrame.std |
N – 1 (ddof=1) |
| Python standard library | statistics.stdev (sample), statistics.pstdev (population) |
Sample and population respectively, by function name |
For spreadsheet users, the CASRAI guide on Excel statistics functions covers the equivalent functions and how they relate to ddof.
Other NumPy functions you may combine with it: NumPy sqrt and NumPy log.
FAQ
Is np.std the population or sample standard deviation?
Population by default, because ddof is zero and the divisor is N. Pass ddof=1 for the sample standard deviation.
How do I get the standard deviation of each column?
Use np.std(a, axis=0). Use axis=1 for each row.
Why does pandas .std() disagree with np.std?
pandas defaults to ddof=1 and skipna=True; NumPy defaults to ddof=0. Use df.std(ddof=0, skipna=False) to match NumPy.
How do I ignore NaN values?
Use np.nanstd, which excludes NaNs from the calculation.
Sources
- NumPy manual, numpy.std (v2.5), checked 2026-10-29.
- NumPy manual, numpy.nanstd, checked 2026-10-29.
- pandas documentation, pandas.DataFrame.std, checked 2026-10-29.
- NumPy, Installing NumPy, checked 2026-10-29.
- Python documentation, statistics module, checked 2026-10-29.







