atelier / src /data /loader.py
adam2504's picture
Initial upload — Atelier luxury demand intelligence demo
89ea727 verified
Raw
History Blame Contribute Delete
3.19 kB
"""
M5-inspired dataset loader.
Generates a long-format DataFrame with realistic retail demand patterns,
then delegates to synthetic.py to overlay luxury-specific signals.
Avoids Kaggle auth requirements so the demo works out-of-the-box.
"""
import numpy as np
import pandas as pd
from src.data.synthetic import apply_luxury_overlay
# ── Catalogue ────────────────────────────────────────────────────────────────
CATEGORIES = {
"leather_goods": ["LG_001", "LG_002", "LG_003", "LG_004", "LG_005"],
"ready_to_wear": ["RTW_001", "RTW_002", "RTW_003"],
"accessories": ["ACC_001", "ACC_002", "ACC_003", "ACC_004"],
"footwear": ["FW_001", "FW_002", "FW_003"],
}
STORES = ["Paris_Flagship", "Tokyo_Ginza", "NYC_5thAve", "Dubai_Mall", "London_Bond"]
PRICE_MAP = {
"leather_goods": (1200, 4500),
"ready_to_wear": (800, 3200),
"accessories": (300, 1200),
"footwear": (600, 2000),
}
def generate_dataset(
start: str = "2021-01-01",
end: str = "2024-12-31",
seed: int = 42,
) -> pd.DataFrame:
"""
Returns a long-format DataFrame with columns:
unique_id, ds, y, price, category, store, event_name
Ready for neuralforecast ingestion (unique_id + ds + y convention).
"""
rng = np.random.default_rng(seed)
dates = pd.date_range(start, end, freq="D")
records = []
for category, items in CATEGORIES.items():
p_low, p_high = PRICE_MAP[category]
for item_id in items:
for store in STORES:
unique_id = f"{item_id}_{store}"
base_demand = rng.integers(5, 40)
price = round(rng.uniform(p_low, p_high), -1) # round to nearest 10
sales = _base_demand_series(dates, base_demand, category, rng)
df_item = pd.DataFrame({
"unique_id": unique_id,
"ds": dates,
"y": sales.clip(0),
"price": price,
"category": category,
"store": store,
"event_name": "",
})
records.append(df_item)
df = pd.concat(records, ignore_index=True)
df = apply_luxury_overlay(df, rng)
df["y"] = df["y"].clip(0).round().astype(int)
return df
def _base_demand_series(
dates: pd.DatetimeIndex,
base: int,
category: str,
rng: np.random.Generator,
) -> np.ndarray:
"""
Compose a realistic base demand curve:
- Weekly seasonality
- Annual seasonality (Q4 Christmas peak, summer trough)
- Slight upward trend
- Gaussian noise
"""
n = len(dates)
t = np.arange(n)
# Trend
trend = base + 0.003 * t
# Annual seasonality — peaks in Nov/Dec, trough in Jan/Feb
annual = 0.25 * base * np.sin(2 * np.pi * (t - 60) / 365)
# Weekly seasonality — weekends sell more in flagship stores
weekly = 0.10 * base * np.sin(2 * np.pi * t / 7)
# Noise
noise = rng.normal(0, base * 0.15, n)
return trend + annual + weekly + noise