Thermal inertia is a building’s resistance to rapid temperature change as its materials store and release heat. A room’s temperature reflects not only current weather but also heat absorbed over preceding hours. In a double-brick house, brickwork and insulation give the building a useful “thermal memory” for forecasting. section 8.1.3
To represent that memory in hourly data, add previous indoor temperatures as lagged features. In pandas, `shift(1)`, `shift(2)`, and `shift(3)` place readings from the preceding one, two, and three hours beside each current reading. Together, those values show both recent temperature and its trajectory. Dropping rows without a full lag history leaves a usable feature table. section 8.1.3
Listing 8.3 Calculating short-term temperature lag features
import pandas as pd
data = {"indoor_temp": [20.0, 20.5, 21.0, 21.5, 22.0, 22.5, 23.0, 23.5,
24.0, 24.5]}
df = pd.DataFrame(data)
df["indoor_temp_lag_1"] = df["indoor_temp"].shift(1)
df["indoor_temp_lag_2"] = df["indoor_temp"].shift(2)
df["indoor_temp_lag_3"] = df["indoor_temp"].shift(3)
df = df.dropna()
print(
df[["indoor_temp", "indoor_temp_lag_1", "indoor_temp_lag_2",
"indoor_temp_lag_3"]]
)
The short pandas listing builds three hourly indoor-temperature lags and removes rows made incomplete by shifting. section 8.1.3
Lagged temperatures can be combined with outdoor temperature, normalized solar readings, and sine–cosine encodings of hour of day to predict indoor temperature one hour ahead. This lets a model learn how strongly recent indoor conditions persist and how quickly weather changes the room. A time-based train/test split and mean absolute error (MAE) compare predictions with later measurements. Forecasting only one hour ahead avoids the compounding errors of repeated longer-range predictions. section 8.3.1 section 8.1.3
Listing 8.6 Indoor temperature prediction with gradient boosting
import pandas as pd
from sklearn.ensemble import HistGradientBoostingRegressor
from sklearn.metrics import mean_absolute_error
df = pd.read_parquet("../datapipeline/2025_export.parquet")
target_col = "temp_indoor"
df = df.dropna(subset=[target_col])
feature_cols = ["t_lag_1h", "t_lag_2h", "t_lag_3h",
"temp_outdoor", "solar_norm", "hour_sin", "hour_cos"
]
split_date = "2025-11-01" #1
train = df.loc[df.index < split_date].copy()
test = df.loc[df.index >= split_date].copy()
X_train, y_train = train[feature_cols], train[target_col]
X_test, y_test = test[feature_cols], test[target_col]
model = HistGradientBoostingRegressor(random_state=42) #2
model.fit(X_train, y_train) #3
test["prediction"] = model.predict(X_test)
mae = mean_absolute_error(test[target_col], test["prediction"])
print(f"Mean Absolute Error: {mae:.4f}")
The gradient-boosting example trains on lag, weather, solar, and time features, then calculates MAE on measurements after a date-based split. section 8.3.1
Thermal inertia also helps explain why temperature is a different forecasting target from household power use. Indoor temperature tends to change smoothly, while electricity demand can spike immediately when an appliance starts. Recent temperature is therefore informative for a short-term temperature forecast, but it does not make power use equally predictable. section 8.3.2 section 8.3.1
