{"cells":[{"cell_type":"markdown","id":"db83b874","metadata":{},"source":"# H&M Personalized Fashion Recommendations: End-to-End Tutorial\n\nThis notebook is a **real executable walkthrough** for Kaggle competition:\n`h-and-m-personalized-fashion-recommendations`.\n\nWhat you will do:\n1. Verify data availability.\n2. Inspect key tables and temporal coverage.\n3. Run a leakage-safe recommendation pipeline.\n4. Evaluate MAP@12 on a temporal validation split.\n5. Generate final Kaggle-formatted submission file.\n"},{"cell_type":"markdown","id":"4f535dda","metadata":{},"source":"## Why this approach\n\nThis competition is recommendation ranking with a strict MAP@12 metric. The baseline here blends:\n- Personal recency-weighted history (customer-level intent)\n- Age-bucket popularity (segment-level prior)\n- Global popularity (cold-start fallback)\n\nValidation is done on the **last 7 days**, with all prior dates as training history to avoid leakage.\n"},{"cell_type":"code","execution_count":1,"id":"448b8eca","metadata":{"execution":{"iopub.execute_input":"2026-06-12T13:10:26.24723Z","iopub.status.busy":"2026-06-12T13:10:26.247064Z","iopub.status.idle":"2026-06-12T13:10:27.055807Z","shell.execute_reply":"2026-06-12T13:10:27.055215Z"}},"outputs":[],"source":"from pathlib import Path\nimport json\nimport polars as pl\n\nfrom hnm_reco.config import PipelineConfig\nfrom hnm_reco.pipeline import run_pipeline\n\nconfig = PipelineConfig()\nproject_root = config.root_dir\nraw_dir = config.raw_data_dir\nprint(f\"Project root: {project_root}\")\nprint(f\"Raw data dir: {raw_dir}\")\n"},{"cell_type":"code","execution_count":2,"id":"cb58dca9","metadata":{"execution":{"iopub.execute_input":"2026-06-12T13:10:27.058956Z","iopub.status.busy":"2026-06-12T13:10:27.058647Z","iopub.status.idle":"2026-06-12T13:10:27.070691Z","shell.execute_reply":"2026-06-12T13:10:27.069967Z"}},"outputs":[],"source":"required_files = [\n    raw_dir / 'transactions_train.csv',\n    raw_dir / 'customers.csv',\n    raw_dir / 'articles.csv',\n    raw_dir / 'sample_submission.csv',\n]\n\nmissing = [str(p) for p in required_files if not p.exists()]\nif missing:\n    raise FileNotFoundError(\n        'Missing Kaggle files. Run `bash scripts/download_data.sh` first. Missing: ' + ', '.join(missing)\n    )\n\nprint('All required competition files are present.')\n"},{"cell_type":"markdown","id":"6f36c2e5","metadata":{},"source":"## Quick data sanity check\n\nRead only a few rows from each table to verify schema and understand key fields.\n"},{"cell_type":"code","execution_count":3,"id":"394ab4ec","metadata":{"execution":{"iopub.execute_input":"2026-06-12T13:10:27.080782Z","iopub.status.busy":"2026-06-12T13:10:27.080523Z","iopub.status.idle":"2026-06-12T13:10:27.554831Z","shell.execute_reply":"2026-06-12T13:10:27.550438Z"}},"outputs":[],"source":"tx_preview = pl.read_csv(raw_dir / 'transactions_train.csv', n_rows=5)\ncustomers_preview = pl.read_csv(raw_dir / 'customers.csv', n_rows=5)\narticles_preview = pl.read_csv(raw_dir / 'articles.csv', n_rows=5)\n\nprint('transactions_train.csv preview:')\ndisplay(tx_preview)\nprint('customers.csv preview:')\ndisplay(customers_preview)\nprint('articles.csv preview:')\ndisplay(articles_preview)\n"},{"cell_type":"code","execution_count":4,"id":"90754703","metadata":{"execution":{"iopub.execute_input":"2026-06-12T13:10:27.558574Z","iopub.status.busy":"2026-06-12T13:10:27.558292Z","iopub.status.idle":"2026-06-12T13:10:35.039865Z","shell.execute_reply":"2026-06-12T13:10:35.039362Z"}},"outputs":[],"source":"tx_dates = (\n    pl.scan_csv(raw_dir / 'transactions_train.csv')\n    .select(pl.col('t_dat').str.strptime(pl.Date, format='%Y-%m-%d', strict=False).alias('t_dat'))\n    .select([\n        pl.col('t_dat').min().alias('min_date'),\n        pl.col('t_dat').max().alias('max_date'),\n        pl.len().alias('rows'),\n    ])\n    .collect()\n)\n\ndisplay(tx_dates)\n"},{"cell_type":"markdown","id":"eeec7096","metadata":{},"source":"## Run full pipeline\n\nThis executes the full workflow from feature prep to validation and submission generation.\n"},{"cell_type":"code","execution_count":5,"id":"b57d5dc3","metadata":{"execution":{"iopub.execute_input":"2026-06-12T13:10:35.041857Z","iopub.status.busy":"2026-06-12T13:10:35.041686Z","iopub.status.idle":"2026-06-12T13:11:14.545112Z","shell.execute_reply":"2026-06-12T13:11:14.544426Z"}},"outputs":[],"source":"artifacts = run_pipeline(config)\nartifacts\n"},{"cell_type":"code","execution_count":6,"id":"d02b9608","metadata":{"execution":{"iopub.execute_input":"2026-06-12T13:11:14.59951Z","iopub.status.busy":"2026-06-12T13:11:14.599287Z","iopub.status.idle":"2026-06-12T13:11:14.604163Z","shell.execute_reply":"2026-06-12T13:11:14.603649Z"}},"outputs":[],"source":"summary = json.loads(Path(artifacts.summary_path).read_text())\nsummary\n"},{"cell_type":"code","execution_count":7,"id":"909fe72a","metadata":{"execution":{"iopub.execute_input":"2026-06-12T13:11:14.612718Z","iopub.status.busy":"2026-06-12T13:11:14.612547Z","iopub.status.idle":"2026-06-12T13:11:14.64224Z","shell.execute_reply":"2026-06-12T13:11:14.641741Z"}},"outputs":[],"source":"submission_preview = pl.read_csv(artifacts.submission_path, n_rows=5)\nsubmission_preview\n"},{"cell_type":"markdown","id":"a6cfbf07","metadata":{},"source":"## Kaggle commands\n\nIf submissions are still open for this competition/account:\n\n```bash\nkaggle competitions submit \\\n  -c h-and-m-personalized-fashion-recommendations \\\n  -f submissions/submission_blended_baseline.csv \\\n  -m \"blended recency-popularity baseline\"\n```\n\nPush notebook to Kaggle Code:\n\n```bash\nkaggle kernels push -p kaggle_kernel\n```\n"}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.12.10"}},"nbformat":4,"nbformat_minor":5}