"""Tiny feature builder for the review pack (no weather, no API calls). Reads data/*.csv, adds calendar + shift-safe lags/rolls. Plain pandas. """ import pandas as pd FEATS_CAT = ["Area", "Region"] FEATS_NUM = ["dow", "is_friday", "is_saturday", "is_weekend", "dom", "month", "year", "woy", "days_since_start", "is_closure", "is_event_date", "lag_1", "lag_7", "lag_14", "lag_28", "lag_56", "roll_mean_7", "roll_mean_28", "roll_std_28", "nonzero_rate_28"] FEATS = FEATS_CAT + FEATS_NUM def build(csv_path): df = pd.read_csv(csv_path, parse_dates=["Date"]) df = df.sort_values(["Area", "Date"]).reset_index(drop=True) df["dow"] = df["Date"].dt.dayofweek.astype("int8") df["is_friday"] = (df["dow"] == 4).astype("int8") df["is_saturday"] = (df["dow"] == 5).astype("int8") df["is_weekend"] = (df["dow"] >= 4).astype("int8") df["dom"] = df["Date"].dt.day.astype("int8") df["month"] = df["Date"].dt.month.astype("int8") df["year"] = df["Date"].dt.year.astype("int16") df["woy"] = df["Date"].dt.isocalendar().week.astype("int16") df["days_since_start"] = (df["Date"] - df["Date"].min()).dt.days.astype("int16") df["Area"] = df["Area"].astype("category") df["Region"] = df["Region"].astype("category") for lag in [1, 7, 14, 28, 56]: df[f"lag_{lag}"] = df.groupby("Area", observed=True)["Volume"].shift(lag).astype("float32") g = df.groupby("Area", observed=True)["Volume"] df["roll_mean_7"] = g.transform(lambda s: s.shift(1).rolling(7).mean()).astype("float32") df["roll_mean_28"] = g.transform(lambda s: s.shift(1).rolling(28).mean()).astype("float32") df["roll_std_28"] = g.transform(lambda s: s.shift(1).rolling(28).std()).astype("float32") df["nonzero_rate_28"] = g.transform( lambda s: s.shift(1).rolling(28).apply(lambda w: (w > 0).mean(), raw=True)).astype("float32") return df def wape(y, p): import numpy as np y = np.asarray(y, dtype=float) p = np.asarray(p, dtype=float) return float(abs(y - p).sum() / max(abs(y).sum(), 1e-9))