NumPy - np.mean() with Examples
The `np.mean()` function computes the arithmetic mean of array elements. For a 1D array, it returns a single scalar value representing the average.
Key Insights
- np.mean() computes arithmetic mean along specified axes with configurable data types and precision control, supporting both simple averages and weighted calculations through broadcasting
- The axis parameter fundamentally changes computation behavior: axis=None flattens arrays, axis=0 operates on columns, axis=1 on rows, and tuple values enable multi-dimensional aggregation
- Memory efficiency and numerical stability require careful dtype selection, especially when working with integer arrays or large datasets where float64 accumulation prevents overflow
Basic Mean Calculation
The np.mean() function computes the arithmetic mean of array elements. For a 1D array, it returns a single scalar value representing the average.
import numpy as np
# Simple 1D array
arr = np.array([10, 20, 30, 40, 50])
mean_value = np.mean(arr)
print(f"Mean: {mean_value}") # Output: Mean: 30.0
# Works with different data types
int_arr = np.array([1, 2, 3, 4, 5], dtype=np.int32)
print(f"Integer array mean: {np.mean(int_arr)}") # Output: 3.0
# Floating point array
float_arr = np.array([1.5, 2.7, 3.2, 4.8])
print(f"Float array mean: {np.mean(float_arr)}") # Output: 3.05
The function automatically promotes integer types to float64 for accurate results. This prevents precision loss during division operations.
Axis-Based Operations
The axis parameter controls which dimension to compute the mean across. This is critical for multi-dimensional arrays.
# 2D array example
matrix = np.array([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
])
# Mean of entire array
overall_mean = np.mean(matrix)
print(f"Overall mean: {overall_mean}") # Output: 5.0
# Mean along axis 0 (column-wise)
column_means = np.mean(matrix, axis=0)
print(f"Column means: {column_means}") # Output: [4. 5. 6.]
# Mean along axis 1 (row-wise)
row_means = np.mean(matrix, axis=1)
print(f"Row means: {row_means}") # Output: [2. 5. 8.]
For 3D arrays, axis selection becomes more nuanced:
# 3D array: (2, 3, 4) shape
arr_3d = np.arange(24).reshape(2, 3, 4)
# Mean along first axis
mean_axis0 = np.mean(arr_3d, axis=0)
print(f"Shape after axis=0: {mean_axis0.shape}") # Output: (3, 4)
# Mean along multiple axes
mean_axes = np.mean(arr_3d, axis=(0, 2))
print(f"Shape after axis=(0,2): {mean_axes.shape}") # Output: (3,)
print(f"Values: {mean_axes}") # Output: [ 5.5 9.5 13.5]
Keepdims Parameter
The keepdims parameter maintains original array dimensionality, which is essential for broadcasting operations.
matrix = np.array([
[10, 20, 30],
[40, 50, 60]
])
# Without keepdims
mean_no_keep = np.mean(matrix, axis=1)
print(f"Shape without keepdims: {mean_no_keep.shape}") # Output: (2,)
print(f"Values: {mean_no_keep}") # Output: [20. 50.]
# With keepdims
mean_keep = np.mean(matrix, axis=1, keepdims=True)
print(f"Shape with keepdims: {mean_keep.shape}") # Output: (2, 1)
print(f"Values:\n{mean_keep}") # Output: [[20.] [50.]]
# Broadcasting example
normalized = matrix - mean_keep
print(f"Normalized matrix:\n{normalized}")
# Output:
# [[-10. 0. 10.]
# [-10. 0. 10.]]
This pattern is fundamental for data normalization and standardization workflows.
Dtype Control and Precision
The dtype parameter controls computation precision and memory usage. Choosing the wrong dtype can cause overflow or unnecessary memory consumption.
# Large integer array
large_ints = np.array([1000000, 2000000, 3000000], dtype=np.int32)
# Default behavior (promotes to float64)
mean_default = np.mean(large_ints)
print(f"Default dtype: {mean_default.dtype}") # Output: float64
# Specify float32 for memory efficiency
mean_f32 = np.mean(large_ints, dtype=np.float32)
print(f"Float32 dtype: {mean_f32.dtype}") # Output: float32
# Demonstrate precision difference
arr = np.array([1.0, 2.0, 3.0, 4.0, 5.0] * 1000000)
mean_f64 = np.mean(arr, dtype=np.float64)
mean_f32 = np.mean(arr, dtype=np.float32)
print(f"Difference: {abs(mean_f64 - mean_f32)}") # Small but measurable
For integer arrays, be aware of potential overflow:
# Overflow scenario
small_ints = np.array([100, 200, 300], dtype=np.int8)
# This safely promotes to float64
safe_mean = np.mean(small_ints)
print(f"Safe mean: {safe_mean}") # Output: 200.0
Weighted Means
While np.mean() doesn’t directly support weights, combine it with broadcasting for weighted calculations:
values = np.array([10, 20, 30, 40])
weights = np.array([1, 2, 3, 4])
# Manual weighted mean
weighted_mean = np.sum(values * weights) / np.sum(weights)
print(f"Weighted mean: {weighted_mean}") # Output: 30.0
# Using np.average (built-in weighted function)
weighted_avg = np.average(values, weights=weights)
print(f"Using np.average: {weighted_avg}") # Output: 30.0
# 2D weighted mean example
matrix = np.array([
[1, 2, 3],
[4, 5, 6]
])
weights_2d = np.array([
[1, 1, 1],
[2, 2, 2]
])
weighted_mean_2d = np.sum(matrix * weights_2d) / np.sum(weights_2d)
print(f"2D weighted mean: {weighted_mean_2d}") # Output: 4.0
Handling NaN Values
Standard np.mean() propagates NaN values. Use np.nanmean() for NaN-aware calculations:
# Array with NaN
arr_with_nan = np.array([1.0, 2.0, np.nan, 4.0, 5.0])
# Regular mean propagates NaN
regular_mean = np.mean(arr_with_nan)
print(f"Regular mean: {regular_mean}") # Output: nan
# NaN-aware mean
nan_mean = np.nanmean(arr_with_nan)
print(f"NaN mean: {nan_mean}") # Output: 3.0
# 2D example
matrix_nan = np.array([
[1.0, 2.0, np.nan],
[4.0, np.nan, 6.0],
[7.0, 8.0, 9.0]
])
# Column-wise with NaN handling
col_means = np.nanmean(matrix_nan, axis=0)
print(f"Column means (NaN-aware): {col_means}") # Output: [4. 5. 7.5]
Performance Optimization
For large datasets, consider memory layout and chunking strategies:
import time
# Large array performance test
large_array = np.random.rand(10000, 10000)
# Standard mean
start = time.time()
mean_std = np.mean(large_array)
time_std = time.time() - start
print(f"Standard mean time: {time_std:.4f}s")
# Axis-specific mean (often faster for specific use cases)
start = time.time()
mean_axis = np.mean(large_array, axis=0)
time_axis = time.time() - start
print(f"Axis mean time: {time_axis:.4f}s")
# Memory-efficient approach for very large datasets
def chunked_mean(arr, chunk_size=1000):
n_chunks = arr.shape[0] // chunk_size
means = []
for i in range(n_chunks):
chunk = arr[i*chunk_size:(i+1)*chunk_size]
means.append(np.mean(chunk))
return np.mean(means)
chunked_result = chunked_mean(large_array)
print(f"Chunked mean: {chunked_result}")
Practical Applications
Real-world scenarios demonstrate np.mean()’s utility:
# Image processing: channel-wise mean
image = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
channel_means = np.mean(image, axis=(0, 1))
print(f"RGB channel means: {channel_means}")
# Time series: moving average
time_series = np.random.randn(1000)
window_size = 10
moving_avg = np.array([
np.mean(time_series[i:i+window_size])
for i in range(len(time_series) - window_size + 1)
])
print(f"Moving average shape: {moving_avg.shape}")
# Statistical normalization (z-score)
data = np.random.randn(100, 5)
mean = np.mean(data, axis=0, keepdims=True)
std = np.std(data, axis=0, keepdims=True)
normalized = (data - mean) / std
print(f"Normalized mean (should be ~0): {np.mean(normalized, axis=0)}")
The np.mean() function provides the foundation for statistical analysis in NumPy. Understanding axis operations, dtype control, and performance characteristics enables efficient data processing across domains from scientific computing to machine learning pipelines.