forecast / features.py
bardd's picture
Upload 63 files
450d514 verified
Raw History Blame Contribute Delete
2.09 kB
"""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))