NumPy Standard Deviation with std(): axis, ddof, and Shape

NumPy std() measures how far values spread around their mean. The most important options are axis, which chooses the dimension to reduce; ddof, which changes the denominator; and keepdims, which preserves reduced dimensions for broadcasting. A standard deviation result is only meaningful when the population or sample interpretation and the numeric dtype are clear.

Quick answer

Call np.std(values) for one standard deviation over all values. Use axis=0 or axis=1 for column or row reductions. The default ddof=0 computes population standard deviation; use ddof=1 for the common sample estimate. Use keepdims=True when the reduced result must broadcast back over the original array.

The official NumPy std reference documents the axis, degrees-of-freedom, dtype, and keepdims behavior. Do not choose ddof merely because one result looks closer to an expected number; choose it from the statistical meaning of the data.

NumPy standard deviation diagram comparing axis ddof keepdims population and sample calculations
axis chooses where to reduce, ddof chooses the denominator correction, and keepdims controls the result shape.

Calculate a scalar standard deviation

With no axis, NumPy treats the array as one collection and returns a scalar. The mean is calculated first, then squared deviations are aggregated and divided according to ddof.

import numpy as np

values = np.array([2.0, 4.0, 6.0, 8.0])
population_std = np.std(values)
sample_std = np.std(values, ddof=1)

print(population_std)
print(sample_std)

For a complete population, ddof=0 is usually the direct description. For a sample used to estimate a larger population, ddof=1 is a common unbiased variance correction. The choice belongs in the analysis specification.

Python Pool infographic showing data values, mean, deviations, and NumPy standard deviation
Observed values: Data values, mean, deviations, and NumPy standard deviation.

Reduce along an axis

A two-dimensional array can be reduced by rows or columns. Read the axis in terms of which dimension disappears. In a matrix with shape (rows, columns), axis=0 combines rows and returns one result per column, while axis=1 combines columns and returns one result per row.

import numpy as np

values = np.array([
    [1.0, 10.0],
    [2.0, 20.0],
    [3.0, 30.0],
])

by_column = np.std(values, axis=0)
by_row = np.std(values, axis=1)

print(by_column)
print(by_row)

Check the result shape before using it in a later calculation. Many broadcasting bugs come from choosing a valid axis that is semantically the wrong one.

Use keepdims for broadcasting

keepdims=True leaves the reduced axis in the result with length one. This makes the result shape compatible with the original array and is useful when subtracting a mean or standard deviation from each row or column.

import numpy as np

values = np.array([
    [1.0, 2.0, 3.0],
    [4.0, 5.0, 6.0],
])
row_std = np.std(values, axis=1, keepdims=True)
centered = values / row_std

print(row_std.shape)
print(centered.shape)

Dividing by a zero standard deviation may produce warnings or invalid values for constant rows. Handle that case according to the model rather than replacing it silently.

Python Pool infographic comparing row, column, flattened, and multidimensional standard deviation
Axis reduction: Row, column, flattened, and multidimensional standard deviation.

Choose ddof deliberately

ddof is subtracted from the number of observations in the denominator. For N values, NumPy uses N - ddof. A high ddof can make the denominator zero or negative for a small sample, so validate it when it comes from configuration.

import numpy as np

values = np.array([4.0, 5.0, 6.0, 7.0])
for ddof in (0, 1):
    print(ddof, np.std(values, ddof=ddof))

Use the same ddof policy for related statistics. Mixing population and sample formulas across columns can make comparisons misleading even when each individual call is valid.

Python Pool infographic comparing ddof zero population spread and ddof one sample spread
Degrees of freedom: Ddof zero population spread and ddof one sample spread.

Control dtype and precision

Floating-point precision affects mean and variance calculations. Integer input is generally promoted for the calculation, while single-precision data may benefit from an explicit higher-precision accumulator when the values are large or nearly equal.

import numpy as np

values = np.array([1000000.1, 1000000.2, 1000000.3], dtype=np.float32)
default_std = np.std(values)
high_precision_std = np.std(values, dtype=np.float64)

print(default_std)
print(high_precision_std)

Choose a dtype from the scale of the data and the accuracy required. A more precise intermediate does not fix a flawed sample definition or invalid missing-value handling.

Handle missing values explicitly

Ordinary np.std() propagates NaN values. If missing values should be ignored, use a documented nan-aware operation such as np.nanstd() and report how many observations remain.

import numpy as np

values = np.array([2.0, np.nan, 6.0, 8.0])
regular = np.std(values)
ignore_missing = np.nanstd(values)

print(regular)
print(ignore_missing)

Ignoring missing values is not always statistically valid. Record the missingness policy and minimum sample size so an apparently precise result does not hide an insufficient dataset.

Python Pool infographic testing NaN, dtype, keepdims, weights, and small sample sizes
Std checks: NaN, dtype, keepdims, weights, and small sample sizes.

Common mistakes

  • Using ddof=1 without deciding whether data is a sample.
  • Reading axis direction backwards.
  • Forgetting keepdims when a result must broadcast.
  • Ignoring NaN propagation or silently dropping missing values.
  • Using low precision for values with severe cancellation.

The reliable workflow is to define the statistical population, choose the reduction axis, set ddof, verify the result shape, and handle missing values explicitly. NumPy provides the calculation; the analysis must provide the meaning.

Interpret small and constant samples

A standard deviation computed from one observation is zero for a population calculation, but a sample calculation with ddof=1 has no degrees of freedom. Decide whether the result should be rejected, represented as missing, or handled by a domain-specific rule before sending it into a model.

Constant data also produces zero spread. Dividing by that value during normalization can create invalid results, so check the spread before using it as a scale factor. A zero is meaningful information, not an error that should always be replaced with one.

Keep units visible in the analysis. Standard deviation has the same units as the original measurements, while variance has squared units. This distinction matters when reporting the result or comparing columns with different scales.

For grouped or time-series data, write down which observations belong together before choosing axis. A correct reduction over the wrong groups is still a wrong statistic, and the resulting array shape may not reveal the mistake.

When comparing groups, report the sample count beside the standard deviation. A spread calculated from two observations should not be presented with the same confidence as one calculated from thousands, even when the numeric result has many decimal places.

Store the chosen ddof and axis alongside generated metrics when results may be reproduced later. Without that metadata, two identical arrays can produce different interpretations even if the calculation itself is deterministic.

For related descriptive statistics, compare NumPy variance and mean before choosing ddof and axis behavior. Read numpy variance and numpy mean for the related workflow.

Frequently Asked Questions

Frequently Asked Questions

How do I calculate standard deviation with NumPy?

Call np.std(values), then choose axis and ddof based on whether the data is a full population or a sample.

What does ddof mean in np.std()?

ddof is subtracted from the observation count in the denominator; ddof=0 is population behavior and ddof=1 is a common sample estimate.

What does axis do in np.std()?

axis selects the dimension or dimensions that are reduced, such as columns with axis=0 or rows with axis=1.

Why use keepdims=True?

keepdims preserves reduced axes with length one so the result can broadcast against the original array.

Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted