File size: 2,088 Bytes
450d514
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
"""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))