NumPy mean(): Calculate array averages with np.mean()

Averaging 8 and 9 gives the first column’s 8.5 through np.mean(scores, axis=0). The useful twist for me is that the axis names the dimension you remove rather than the one you keep.

You’ll work with an average that gives every included value equal influence. You’ll make sense of that np.mean result as the included values’ sum divided by their count.

What np.mean computes

NumPy mean is an arithmetic average, the sum of the included values divided by their count. The np.mean function can reduce an entire array to one number or calculate separate averages along an axis. An axis is a numbered dimension of the array.

For a two-dimensional array, axis=0 identifies the row dimension and axis=1 identifies the column dimension. Reducing the row dimension leaves a mean for each column, so the axis names what disappears rather than what you keep.

ParameterDecision it controls
axisWhich dimension to reduce, or None for all values
keepdimsWhether reduced dimensions remain with size one
whereWhich values contribute to the sum and count
dtypeThe numeric type used for accumulation and the result

The NumPy mean reference also accepts array-like input, so you can pass a numeric Python list without first converting it yourself. Use np.average when you need unequal weights, because np.mean gives each included value equal influence.

Prerequisites for running the NumPy examples

You need Python and NumPy in the same environment, plus enough Python syntax to create a list and call a function. I ran these examples on Linux with Python 3.14.7 and NumPy 2.5.3 in a fresh virtual environment.

Install NumPy through the Python interpreter that will execute your examples. The commands create an isolated environment and install the available release without a version constraint.

python3 -m venv .venv
.venv/bin/python -m pip install numpy

Run the Python blocks in order in one interpreter session, since the later blocks reuse scores and the np import. The matrix represents two rows of three numeric scores, and its unequal dimensions make a wrong axis visible.

Step 1: Calculate whole-array and axis means

Start with one overall average, then compare it with an average for each column and each row. The np alias comes from import numpy as np, and np.array turns the nested lists into a rectangular array.

import numpy as np

scores = np.array([[8, 6, 7], [9, 5, 8]])
daily = np.array([8, 6, 7])
print("1D mean:", np.mean(daily))
print("scores:", scores, sep="\n")
print("shape:", scores.shape)
print("overall:", np.mean(scores))
print("columns:", np.mean(scores, axis=0))
print("column result shape:", np.mean(scores, axis=0).shape)
print("rows:", np.mean(scores, axis=1))
print("row result shape:", np.mean(scores, axis=1).shape)

The overall mean is 7.166666666666667, because the sum of 43 is divided by six entries. With axis=0, the pairs 8 and 9 contribute to the first column mean of 8.5, and the result contains three means.

Terminal output showing whole-array, column, and row means with their NumPy result shapes
The same scores produce column means with shape (3,) and row means with shape (2,). The lower output also shows the retained row dimension used for centering.

Using axis=1 gives row means of 7.0 and 7.33333333, with the latter rounded in the printed array. Each row contributes three entries to its own mean, so the output retains the two-row dimension.

If your input is a list of separate arrays, combine equally shaped rows into one rectangular array before reducing the row dimension. Averaging each row inside a Python loop produces row means, even if that inner one-dimensional call uses axis=0.

Step 2: Keep the reduced dimension for subtraction

Subtracting each row’s mean centers that row around zero, but the shapes must align first. Broadcasting is NumPy’s rule for combining arrays of different shapes, comparing dimensions from the right and accepting equal sizes or a size of one.

The row mean has shape (2,), whose trailing size cannot align with the three columns in scores. Set keepdims=True to retain a column dimension of size one, allowing one row mean to apply across that row.

row_means = np.mean(scores, axis=1, keepdims=True)
centered = scores - row_means
print("row means:", row_means, sep="\n")
print("retained shape:", row_means.shape)
print("centered rows:", centered, sep="\n")

I got row_means.shape equal to (2, 1), and the first centered row was [1, -1, 0]. The subtraction leaves scores unchanged because it creates a separate result array.

ArrayShapeHow it aligns
scores(2, 3)Two rows with three columns
Row means without keepdims(2,)Trailing size two conflicts with three columns
Row means with keepdims(2, 1)Trailing size one expands across each row

NumPy’s broadcasting rules explain why the extra dimension changes the subtraction. For column-wise centering, change the axis to 0 and retain its dimension in the same way.

Step 3: Choose which values contribute to the average

NaN means “not a number.” An ordinary mean containing NaN returns NaN, while np.nanmean excludes it from both the sum and the count. Use that exclusion when NaN marks a missing measurement, rather than replacing the measurement with zero.

Zero is different because it is a numeric value and contributes to np.mean by default. Exclude it with a where mask only if your data defines zero as missing, since discarding a measured zero changes the average.

measurements = np.array([2.0, np.nan, 4.0])
print("ordinary mean with NaN:", np.mean(measurements))
print("NaN-aware mean:", np.nanmean(measurements))

counts = np.array([0.0, 2.0, 4.0])
print("mean including zero:", np.mean(counts))
print("mean excluding zero with where:", np.mean(counts, where=counts != 0))

values = np.array([1.0, 4.0, 9.0])
weights = np.array([1.0, 2.0, 1.0])
print("ordinary mean:", np.mean(values))
print("weighted mean:", np.average(values, weights=weights))

float_values = np.array([1.2, 1.3], dtype=np.float32)
print("integer input mean dtype:", np.mean(scores).dtype)
print("float32 input mean dtype:", np.mean(float_values).dtype)
print("float64 accumulation dtype:", np.mean(float_values, dtype=np.float64).dtype)

The NaN-aware mean is 3.0 because only 2.0 and 4.0 contribute. The zero mask also returns 3.0 for its own input, replacing a sum divided by three entries with a sum divided by two included entries.

Terminal output comparing NaN handling, zero masks, weighted averages, and NumPy mean dtypes
The zero-selection rule changes 2.0 to 3.0, while unequal weights change 4.666666666666667 to 4.5. The final lines show the numeric types used by the reductions.

The where argument of np.mean is a Boolean inclusion mask, meaning an array of True or False decisions. The separate np.where function selects values or finds positions, so calling it does not itself calculate a mean.

With weights [1, 2, 1], the value 4 contributes twice, giving a weighted sum of 18 divided by a total weight of 4. I got 4.5 from np.average and 4.666666666666667 from np.mean for the same values.

Choose np.average with weights for unequal contributions, with compatible weight shapes and a nonzero sum, because zero total weight raises ZeroDivisionError.

Handle empty selections and floating-point precision

An average needs at least one contributing value, so an empty selection has no defined arithmetic mean. I excluded every entry with where and got NaN with RuntimeWarning, which means a mask needs a no-data branch as well as a numeric result branch.

The nanmean reference documents the same no-data boundary for an all-NaN slice. You can expose those warnings in a small diagnostic before deciding whether your application should skip that slice or flag it for missing data.

import warnings

with warnings.catch_warnings(record=True) as seen:
    warnings.simplefilter("always", RuntimeWarning)
    empty_mean = np.mean(counts, where=np.zeros(counts.shape, dtype=bool))
    missing_mean = np.nanmean(np.array([np.nan, np.nan]))
print("empty selection:", empty_mean)
print("all-NaN selection:", missing_mean)
for warning in seen:
    print(type(warning.message).__name__ + ":", warning.message)

signal = np.zeros((2, 512 * 512), dtype=np.float32)
signal[0, :] = 1.0
signal[1, :] = 0.1
print("float32 mean:", float(np.mean(signal)))
print("float64 accumulator:", float(np.mean(signal, dtype=np.float64)))

The precision example stores the same number of 1.0 and 0.1 values in float32, a floating-point type with limited precision. A float64 accumulator reduces rounding during summation, but cannot recover precision already lost when the input was stored.

Terminal output showing undefined means for empty and all-NaN selections, with float32 and float64 accumulator results
Empty selections return NaN with warnings. The two accumulation results differ because the numeric precision differs.
Input typeDefault mean behaviorWhen to change it
Integerfloat64 accumulation and resultKeep the default for fractional averages
float32float32 accumulation and resultUse dtype=np.float64 when accumulation accuracy warrants it
float16float32 intermediates with a float16 resultSet dtype explicitly if the result needs wider precision

Changing dtype does not give an empty selection any contributing values, so its mean remains undefined even with a wider accumulator.

Verify centered rows against a zero mean

After subtracting the retained row means, calculate the row averages again and compare them with zero using a tolerance. Floating-point subtraction can leave a tiny remainder, so exact equality would test a stricter condition than centering requires.

centered_means = np.mean(centered, axis=1)
print("centered means:", centered_means)
assert row_means.shape == (scores.shape[0], 1)
assert np.allclose(centered_means, 0.0, atol=1e-12)
print("row centering passed")

The assertion checks both the reduction shape and the resulting row averages. If you switch to column centering, switch the verification axis too, otherwise you would be checking a different set of averages.

NumPy mean questions

The same mean operation works with array-like input or the method on an existing NumPy array. Keep the array’s dimension count in mind when choosing the axis, since a one-dimensional input has no axis=1.

Can I pass a Python list directly to np.mean?

Yes. NumPy accepts array-like numeric input and attempts to convert it to an array before calculating the mean.

Can I use scores.mean() instead of np.mean(scores)?

Yes. The ndarray mean method calculates the same reduction and accepts axis and keepdims arguments.

Why does axis=1 fail on a one-dimensional array?

A one-dimensional array has only axis=0. Use the default mean for one average, or build a two-dimensional array before requesting row-wise means.

Piyush Bhujbal
Piyush Bhujbal
Articles: 35