weather.derived.population_weighted_average

weather.derived.population_weighted_average(frames, weights)

Combine per-location weather frames into one demand-weighted index.

Forms :math:\sum_i \tilde{w}_i X_i where :math:\tilde{w} are the weights normalised to sum to one. All frames must share the same index and the same columns (the identical Open-Meteo schema fetched per location), so the result is a single frame with that schema representing a national, population-weighted weather signal (Zimmermann & Ziel 2025, zimm25a).

Parameters

Name Type Description Default
frames Sequence[pd.DataFrame] One weather frame per location, all with the same DatetimeIndex and the same columns. required
weights Sequence[float] One non-negative weight per frame (e.g. city population). They are normalised internally; their absolute scale is irrelevant. required

Returns

Name Type Description
pd.DataFrame pd.DataFrame: The weighted-average frame, same index and columns as the
pd.DataFrame inputs (column order taken from frames[0]).

Raises

Name Type Description
ValueError If frames is empty, lengths mismatch, weights are negative or sum to zero, or the frames disagree on index or columns.

Examples

import pandas as pd
from spotforecast2_safe.weather.derived import population_weighted_average

idx = pd.date_range("2023-06-01", periods=3, freq="h", tz="UTC")
a = pd.DataFrame({"temperature_2m": [10.0, 10.0, 10.0]}, index=idx)
b = pd.DataFrame({"temperature_2m": [20.0, 20.0, 20.0]}, index=idx)
out = population_weighted_average([a, b], [3.0, 1.0])
print(out["temperature_2m"].tolist())  # (3*10 + 1*20)/4 == 12.5
[12.5, 12.5, 12.5]