Compute a weighted mean without losing its denominator
Compute a weighted mean without losing its denominator
A weighted mean gives each value influence proportional to its weight. Its denominator is the total weight, not the number of observations. Losing that denominator is a common error: summing value * weight and dividing by len(values) produces a different quantity whenever weights are not all one.
The helper checks that the two sequences have matching lengths, sums the products for the numerator, and divides by math.fsum(weights) for the denominator. The sample scores are 80, 90, and 70 with weights 2, 1, and 3. Their weighted total is 460 and their total weight is 6, giving approximately 76.6667. The assertions verify both totals and the computed result. math.fsum is used for floating-point summation because it tracks intermediate partial sums; it does not make the final division exact.
A zero total weight has no defined weighted mean, so the function raises ValueError. Negative weights are permitted here mathematically but may be invalid for counts, probabilities, or survey weights; impose that domain rule if needed. Empty input also reaches the zero-total-weight check. This example does not address missing values or choose a rounding policy beyond display formatting.
math.fsum is documented in the Python math reference and is available since Python 2.6, including all supported Python 3 versions.
AI assistance disclosure: This article was drafted with AI assistance and should be reviewed for the domain meaning of weights.
import math
def weighted_mean(values, weights):
if len(values) != len(weights):
raise ValueError("values and weights must have the same length")
denominator = math.fsum(weights)
if denominator == 0:
raise ValueError("total weight must not be zero")
numerator = math.fsum(value * weight for value, weight in zip(values, weights))
return numerator / denominator
scores = [80.0, 90.0, 70.0]
weights = [2.0, 1.0, 3.0]
mean = weighted_mean(scores, weights)
assert math.fsum(weights) == 6.0
assert math.fsum(score * weight for score, weight in zip(scores, weights)) == 460.0
assert math.isclose(mean, 460.0 / 6.0)
print(f"weighted mean={mean:.2f}")
weighted mean=76.67
Comments
Post a Comment