Skip to main content

Overview

Masked arrays support most NumPy operations while automatically handling masked values. This page covers arithmetic operations, comparisons, reductions, and other common operations.

Arithmetic Operations

Masked arrays support all standard arithmetic operators. The resulting mask is the union of the input masks.

Basic Arithmetic

import numpy as np
import numpy.ma as ma

# Create masked arrays
x = ma.array([1, 2, 3, 4, 5], mask=[0, 0, 1, 0, 0])
y = ma.array([10, 20, 30, 40, 50], mask=[0, 1, 0, 0, 0])

print("x:", x)
# x: [1 2 -- 4 5]

print("y:", y)
# y: [10 -- 30 40 50]

# Addition
print("x + y:", x + y)
# x + y: [11 -- -- 44 55]

# Subtraction
print("x - y:", x - y)
# x - y: [-9 -- -- -36 -45]

# Multiplication
print("x * y:", x * y)
# x * y: [10 -- -- 160 250]

# Division
print("y / x:", y / x)
# y / x: [10.0 -- -- 10.0 10.0]

# Power
print("x ** 2:", x ** 2)
# x ** 2: [1 4 -- 16 25]

Mask Propagation

When operating on masked arrays, masks are combined:
import numpy.ma as ma

x = ma.array([1, 2, 3, 4], mask=[0, 0, 1, 0])
y = ma.array([10, 20, 30, 40], mask=[0, 1, 0, 0])

result = x + y
print("Result:", result)
# Result: [11 -- -- 44]

print("Result mask:", result.mask)
# Result mask: [False True True False]
# Position 1: masked in y
# Position 2: masked in x

Operations with Scalars

import numpy.ma as ma

x = ma.array([1, 2, 3, 4, 5], mask=[0, 0, 1, 0, 0])

# Scalar operations
print(x + 10)
# [11 12 -- 14 15]

print(x * 2)
# [2 4 -- 8 10]

print(x / 2.0)
# [0.5 1.0 -- 2.0 2.5]

Comparison Operations

Comparison operations return masked boolean arrays.

Basic Comparisons

import numpy as np
import numpy.ma as ma

x = ma.array([1, 2, 3, 4, 5], mask=[0, 0, 1, 0, 0])

# Greater than
print(x > 2)
# [False False -- True True]

# Less than
print(x < 4)
# [True True -- False False]

# Equal to
print(x == 2)
# [False True -- False False]

# Not equal to
print(x != 2)
# [True False -- True True]

Array Comparisons

import numpy.ma as ma

x = ma.array([1, 2, 3, 4], mask=[0, 0, 1, 0])
y = ma.array([1, 3, 3, 4], mask=[0, 0, 0, 0])

print(x == y)
# [True False -- True]

print(x > y)
# [False False -- False]

Reduction Operations

Reduction operations compute aggregates while excluding masked values.

Sum and Product

import numpy.ma as ma

x = ma.array([1, 2, 3, 4, 5], mask=[0, 0, 1, 0, 0])

print("Sum:", x.sum())
# Sum: 12 (excludes masked value 3)

print("Product:", x.prod())
# Product: 40 (1 * 2 * 4 * 5)

print("Cumulative sum:", x.cumsum())
# Cumulative sum: [1 3 -- 7 12]

Mean, Median, and Standard Deviation

import numpy as np
import numpy.ma as ma

data = np.array([1.0, 2.0, 3.0, 100.0, 4.0, 5.0])  # 100 is an outlier
x = ma.masked_greater(data, 50)

print("Mean:", x.mean())
# Mean: 3.0

print("Median:", ma.median(x))
# Median: 3.0

print("Std:", x.std())
# Std: 1.4142135623730951

print("Variance:", x.var())
# Variance: 2.0

Min and Max

import numpy.ma as ma

x = ma.array([5, 2, 8, 1, 9, 3], mask=[0, 0, 1, 0, 0, 1])

print("Min:", x.min())
# Min: 1

print("Max:", x.max())
# Max: 9

print("Arg min:", x.argmin())
# Arg min: 3

print("Arg max:", x.argmax())
# Arg max: 4

print("Peak-to-peak:", x.ptp())
# Peak-to-peak: 8 (max - min)

Reductions Along Axes

import numpy as np
import numpy.ma as ma

# 2D masked array
data = np.array([[1, 2, 3],
                 [4, 5, 6],
                 [7, 8, 9]])
mask = np.array([[0, 0, 1],
                 [0, 1, 0],
                 [1, 0, 0]])
x = ma.array(data, mask=mask)

print("Array:")
print(x)
# [[1 2 --]
#  [4 -- 6]
#  [-- 8 9]]

# Sum along axis 0 (columns)
print("Sum axis 0:", x.sum(axis=0))
# Sum axis 0: [5 10 15]

# Sum along axis 1 (rows)
print("Sum axis 1:", x.sum(axis=1))
# Sum axis 1: [3 10 17]

# Mean along axis 0
print("Mean axis 0:", x.mean(axis=0))
# Mean axis 0: [2.5 5.0 7.5]

Logical Operations

Logical operations work element-wise on masked boolean arrays.
import numpy as np
import numpy.ma as ma

x = ma.array([1, 2, 3, 4, 5], mask=[0, 0, 1, 0, 0])

# Logical AND
result = (x > 1) & (x < 5)
print(result)
# [False True -- True False]

# Logical OR
result = (x < 2) | (x > 4)
print(result)
# [True False -- False True]

# Logical NOT
result = ~(x > 3)
print(result)
# [True True -- False False]

All and Any

import numpy.ma as ma

x = ma.array([True, True, False, True], mask=[0, 0, 1, 0])

print("All (excluding masked):", x.all())
# All (excluding masked): True (all unmasked values are True)

print("Any:", x.any())
# Any: True

y = ma.array([False, False, True, False], mask=[0, 0, 1, 0])
print("All:", y.all())
# All: False

Universal Functions (ufuncs)

Most NumPy ufuncs work with masked arrays.

Mathematical Functions

import numpy as np
import numpy.ma as ma

x = ma.array([0.0, 0.5, 1.0, 1.5, 2.0], mask=[0, 0, 1, 0, 0])

print("Square root:", ma.sqrt(x))
# Square root: [0.0 0.707... -- 1.224... 1.414...]

print("Exponential:", ma.exp(x))
# Exponential: [1.0 1.648... -- 4.481... 7.389...]

print("Logarithm:", ma.log(x[1:]))
# Logarithm: [-0.693... -- 0.405... 0.693...]

print("Sin:", ma.sin(x))
# Sin: [0.0 0.479... -- 0.997... 0.909...]

Rounding and Clipping

import numpy.ma as ma

x = ma.array([1.2, 2.5, 3.8, 4.1, 5.9], mask=[0, 0, 1, 0, 0])

print("Round:", ma.round(x))
# Round: [1. 2. -- 4. 6.]

print("Floor:", ma.floor(x))
# Floor: [1. 2. -- 4. 5.]

print("Ceil:", ma.ceil(x))
# Ceil: [2. 3. -- 5. 6.]

print("Clip:", ma.clip(x, 2, 5))
# Clip: [2. 2.5 -- 4.1 5.]

Array Manipulation

Reshaping

import numpy.ma as ma

x = ma.array([1, 2, 3, 4, 5, 6], mask=[0, 0, 1, 0, 1, 0])

# Reshape to 2D
y = x.reshape((2, 3))
print(y)
# [[1 2 --]
#  [4 -- 6]]

print(y.mask)
# [[False False True]
#  [False True False]]

Transpose

import numpy as np
import numpy.ma as ma

data = np.arange(6).reshape((2, 3))
mask = [[0, 1, 0], [0, 0, 1]]
x = ma.array(data, mask=mask)

print("Original:")
print(x)
# [[0 -- 2]
#  [3 4 --]]

print("Transposed:")
print(x.T)
# [[0 3]
#  [-- 4]
#  [2 --]]

Concatenation

import numpy.ma as ma

x = ma.array([1, 2, 3], mask=[0, 1, 0])
y = ma.array([4, 5, 6], mask=[1, 0, 0])

result = ma.concatenate([x, y])
print(result)
# [1 -- 3 -- 5 6]

print(result.mask)
# [False True False True False False]

Filling and Conversion

Filling Masked Values

import numpy.ma as ma

x = ma.array([1, 2, 3, 4, 5], mask=[0, 0, 1, 0, 1])

# Get filled array (default fill value)
print(x.filled())
# [1 2 999999 4 999999]

# Custom fill value
print(x.filled(fill_value=0))
# [1 2 0 4 0]

print(x.filled(fill_value=-1))
# [1 2 -1 4 -1]

Compressed (Remove Masked)

import numpy.ma as ma

x = ma.array([1, 2, 3, 4, 5], mask=[0, 0, 1, 0, 1])

# Get only unmasked values
compressed = x.compressed()
print(compressed)
# [1 2 4]

print(type(compressed))
# <class 'numpy.ndarray'> (regular array, not masked)

Practical Examples

Example 1: Time Series Analysis

import numpy as np
import numpy.ma as ma

# Temperature readings with some missing values
temps = np.array([22.5, 23.1, -999, 22.8, 23.5, -999, 22.9, 23.2])
missing_mask = (temps == -999)
temps_ma = ma.array(temps, mask=missing_mask)

print(f"Mean temperature: {temps_ma.mean():.2f}°C")
print(f"Temperature range: {temps_ma.ptp():.2f}°C")
print(f"Std deviation: {temps_ma.std():.2f}°C")

# Mean temperature: 23.00°C
# Temperature range: 1.00°C
# Std deviation: 0.32°C

Example 2: Image Processing

import numpy as np
import numpy.ma as ma

# Simulate grayscale image with invalid pixels
image = np.random.randint(0, 256, (10, 10), dtype=np.uint8)

# Mark pixels that are too bright or too dark as invalid
mask = (image < 10) | (image > 245)
image_ma = ma.array(image, mask=mask)

print(f"Valid pixels: {image_ma.count()}")
print(f"Mean intensity: {image_ma.mean():.1f}")
print(f"Median intensity: {ma.median(image_ma):.1f}")

Example 3: Statistical Analysis

import numpy as np
import numpy.ma as ma

# Dataset with outliers
data = np.array([12, 15, 14, 13, 150, 11, 16, 200, 15, 12])

# Remove outliers using IQR method
q1 = np.percentile(data, 25)
q3 = np.percentile(data, 75)
iqr = q3 - q1
lower_bound = q1 - 1.5 * iqr
upper_bound = q3 + 1.5 * iqr

# Mask outliers
data_clean = ma.masked_outside(data, lower_bound, upper_bound)

print(f"Original mean: {data.mean():.2f}")
# Original mean: 45.80

print(f"Cleaned mean: {data_clean.mean():.2f}")
# Cleaned mean: 13.50

print(f"Outliers removed: {data_clean.mask.sum()}")
# Outliers removed: 2

Example 4: Multi-dimensional Operations

import numpy as np
import numpy.ma as ma

# Simulate 3D data (time × height × location)
data = np.random.randn(5, 10, 8)

# Mark some measurements as invalid
mask = np.random.random((5, 10, 8)) > 0.9
data_ma = ma.array(data, mask=mask)

# Calculate temporal mean at each position
temporal_mean = data_ma.mean(axis=0)
print(f"Temporal mean shape: {temporal_mean.shape}")  # (10, 8)

# Calculate vertical profile (average over locations)
vertical_profile = data_ma.mean(axis=(0, 2))
print(f"Vertical profile shape: {vertical_profile.shape}")  # (10,)

# Overall statistics
print(f"Total measurements: {data.size}")
print(f"Valid measurements: {data_ma.count()}")
print(f"Invalid measurements: {data_ma.mask.sum()}")

Performance Tips

In-Place Operations

Use in-place operations to avoid creating unnecessary copies:
x = ma.array([1, 2, 3, 4], mask=[0, 0, 1, 0])
x += 10  # In-place addition
x *= 2   # In-place multiplication

Avoid Loops

Use vectorized operations instead of loops:
# Bad (slow)
result = []
for val in x:
    result.append(val * 2 if not ma.is_masked(val) else ma.masked)

# Good (fast)
result = x * 2

Use compressed() for Regular Operations

If you need to perform operations that don’t support masking, use compressed():
x = ma.array([1, 2, 3, 4, 5], mask=[0, 0, 1, 0, 0])
valid_data = x.compressed()
result = some_function(valid_data)

See Also

Build docs developers (and LLMs) love