{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceType":"competition","sourceId":38760,"databundleVersionId":4493939}],"dockerImageVersionId":31286,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import json\nimport pandas as pd\nfrom collections import defaultdict\nfrom tqdm import tqdm\nimport gc\n\nDATA_PATH = \"/kaggle/input/competitions/otto-recommender-system\"\n\nTYPE_WEIGHTS = {\n    \"clicks\": 1,\n    \"carts\": 6,\n    \"orders\": 40\n}\n\nDEBUG = True\nMAX_SESSIONS = 200_000 if DEBUG else None","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-03-18T15:33:43.272725Z","iopub.execute_input":"2026-03-18T15:33:43.273460Z","iopub.status.idle":"2026-03-18T15:33:43.279118Z","shell.execute_reply.started":"2026-03-18T15:33:43.273423Z","shell.execute_reply":"2026-03-18T15:33:43.278186Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def build_covisit_matrices():\n\n    clicks_clicks = defaultdict(lambda: defaultdict(int))\n    clicks_carts  = defaultdict(lambda: defaultdict(int))\n    clicks_orders = defaultdict(lambda: defaultdict(int))\n\n    with open(f\"{DATA_PATH}/train.jsonl\", \"r\") as f:\n\n        for idx, line in enumerate(tqdm(f)):\n\n            if MAX_SESSIONS and idx >= MAX_SESSIONS:\n                break\n\n            session = json.loads(line)\n            events = session[\"events\"]\n\n            aids = [e[\"aid\"] for e in events]\n            types = [e[\"type\"] for e in events]\n\n            for i in range(len(aids)):\n                aid_i = aids[i]\n                type_i = types[i]\n\n                if type_i != \"clicks\":\n                    continue\n\n                for j in range(i + 1, len(aids)):\n                    aid_j = aids[j]\n                    type_j = types[j]\n\n                    weight = TYPE_WEIGHTS[type_j]\n\n                    if type_j == \"clicks\":\n                        clicks_clicks[aid_i][aid_j] += weight\n                    elif type_j == \"carts\":\n                        clicks_carts[aid_i][aid_j] += weight\n                    else:\n                        clicks_orders[aid_i][aid_j] += weight\n\n    return clicks_clicks, clicks_carts, clicks_orders","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-18T15:33:43.281046Z","iopub.execute_input":"2026-03-18T15:33:43.281426Z","iopub.status.idle":"2026-03-18T15:33:43.306197Z","shell.execute_reply.started":"2026-03-18T15:33:43.281387Z","shell.execute_reply":"2026-03-18T15:33:43.305223Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def keep_top_k(matrix, k=40):\n\n    result = {}\n\n    for aid, neighbors in matrix.items():\n        sorted_neighbors = sorted(neighbors.items(), key=lambda x: -x[1])[:k]\n        result[aid] = dict(sorted_neighbors)\n\n    return result","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-18T15:33:43.307706Z","iopub.execute_input":"2026-03-18T15:33:43.308397Z","iopub.status.idle":"2026-03-18T15:33:43.327426Z","shell.execute_reply.started":"2026-03-18T15:33:43.308355Z","shell.execute_reply":"2026-03-18T15:33:43.326567Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"Строим матрицы...\")\n\nclicks2clicks, clicks2carts, clicks2orders = build_covisit_matrices()\n\nclicks2clicks = keep_top_k(clicks2clicks)\nclicks2carts  = keep_top_k(clicks2carts)\nclicks2orders = keep_top_k(clicks2orders)\n\ngc.collect()\n\nprint(\"Готово!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-18T15:33:43.328674Z","iopub.execute_input":"2026-03-18T15:33:43.329836Z","iopub.status.idle":"2026-03-18T15:40:36.773728Z","shell.execute_reply.started":"2026-03-18T15:33:43.329806Z","shell.execute_reply":"2026-03-18T15:40:36.764393Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def make_recommendations(events):\n\n    if len(events) == 0:\n        return [1460571, 1460572, 1460573]\n\n    aids = [e[\"aid\"] for e in events]\n\n    unique_recent = list(dict.fromkeys(aids[::-1]))\n\n    last_aid = aids[-1]\n\n    candidates = []\n    \n    for matrix in (clicks2orders, clicks2carts, clicks2clicks):\n        if last_aid in matrix:\n            candidates.extend(list(matrix[last_aid].keys()))\n\n    result = unique_recent + candidates\n\n    # fallback\n    result.extend([1460571, 1460572, 1460573])\n\n    return list(dict.fromkeys(result))[:20]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-18T15:40:37.057430Z","iopub.execute_input":"2026-03-18T15:40:37.106330Z","iopub.status.idle":"2026-03-18T15:40:38.167498Z","shell.execute_reply.started":"2026-03-18T15:40:37.076665Z","shell.execute_reply":"2026-03-18T15:40:38.166575Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"Создаём submission...\")\n\nrows = []\n\nwith open(f\"{DATA_PATH}/test.jsonl\", \"r\") as f:\n\n    for line in tqdm(f):\n\n        session = json.loads(line)\n        session_id = session[\"session\"]\n\n        recs = make_recommendations(session[\"events\"])\n        recs_str = \" \".join(map(str, recs))\n\n        for t in [\"clicks\", \"carts\", \"orders\"]:\n            rows.append({\n                \"session_type\": f\"{session_id}_{t}\",\n                \"labels\": recs_str\n            })\n\nsubmission = pd.DataFrame(rows)\nsubmission.to_csv(\"submission.csv\", index=False)\n\nprint(\"Готово! Размер:\", submission.shape)\nsubmission.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-18T15:40:38.168778Z","iopub.execute_input":"2026-03-18T15:40:38.169201Z","iopub.status.idle":"2026-03-18T15:42:09.647406Z","shell.execute_reply.started":"2026-03-18T15:40:38.169172Z","shell.execute_reply":"2026-03-18T15:42:09.646218Z"}},"outputs":[],"execution_count":null}]}