{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":102335,"databundleVersionId":12518947,"sourceType":"competition"}],"dockerImageVersionId":31089,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\n\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-08-04T09:04:18.496515Z","iopub.execute_input":"2025-08-04T09:04:18.496808Z","iopub.status.idle":"2025-08-04T09:04:18.513853Z","shell.execute_reply.started":"2025-08-04T09:04:18.496784Z","shell.execute_reply":"2025-08-04T09:04:18.512500Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import polars as pl\n\ntrain_df = pl.read_csv('/kaggle/input/cmi-detect-behavior-with-sensor-data/train.csv')\ntrain_demo_df = pl.read_csv(\"/kaggle/input/cmi-detect-behavior-with-sensor-data/train_demographics.csv\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-04T09:04:18.514730Z","iopub.execute_input":"2025-08-04T09:04:18.515054Z","iopub.status.idle":"2025-08-04T09:04:31.457326Z","shell.execute_reply.started":"2025-08-04T09:04:18.515021Z","shell.execute_reply":"2025-08-04T09:04:31.456311Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.preprocessing import LabelEncoder\n\nGESTURE_LABELS = train_df[\"gesture\"].unique().sort().to_numpy()\n\nle = LabelEncoder()\nle.fit(GESTURE_LABELS)\n\ngesture_ids = le.transform(train_df[\"gesture\"].to_numpy())\ntrain_df = train_df.with_columns(pl.Series(\"gesture_id\", gesture_ids).cast(pl.Int32))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-04T09:04:31.459254Z","iopub.execute_input":"2025-08-04T09:04:31.459600Z","iopub.status.idle":"2025-08-04T09:04:33.309927Z","shell.execute_reply.started":"2025-08-04T09:04:31.459575Z","shell.execute_reply":"2025-08-04T09:04:33.308797Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# result = train_df.group_by(\"sequence_id\").agg(\n#     pl.col(\"subject\").n_unique()\n# )\n# print(result)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-04T09:04:33.310850Z","iopub.execute_input":"2025-08-04T09:04:33.311225Z","iopub.status.idle":"2025-08-04T09:04:33.315716Z","shell.execute_reply.started":"2025-08-04T09:04:33.311204Z","shell.execute_reply":"2025-08-04T09:04:33.314516Z"},"jupyter":{"source_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nfrom tqdm import tqdm\n\ndef data_process(sequence_df, demo_df):\n    exclude_cols = {\"row_id\", \"sequence_type\", \"sequence_id\", \"sequence_counter\", \"subject\", \"orientation\", \"behavior\", \"phase\", \"gesture\", \"gesture_id\"}\n    value_cols = [col for col in sequence_df.columns if col not in exclude_cols]\n\n    features = []\n    for seq_id, group in tqdm(sequence_df.group_by(\"sequence_id\")):\n        group = group.with_columns([\n            pl.when(pl.col(col).is_null().all())\n            .then(pl.lit(0))\n            .otherwise(pl.col(col).fill_null(pl.col(col).mean()))\n            .alias(col)\n            for col in value_cols\n        ])\n\n        if group[\"subject\"].n_unique() > 1:\n            print(\"Warning: Duplicate `gesture` detected! The same `sequence_id` cannot have multiple `gesture`.\")\n        \n        subject = group[\"subject\"].first()\n        row = {\n            \"sequence_id\": seq_id[0],\n            \"subject\": subject\n        }\n        for col in value_cols:\n            values = group[col].to_numpy()\n            row[f\"{col}_mean\"] = values.mean()\n            row[f\"{col}_std\"] = values.std()\n            row[f\"{col}_min\"] = values.min()\n            row[f\"{col}_max\"] = values.max()\n            row[f\"{col}_median\"] = np.median(values)\n            row[f\"{col}_q25\"] = np.percentile(values, 25)\n            row[f\"{col}_q75\"] = np.percentile(values, 75)\n\n        features.append(row)\n\n    feature_df = pd.DataFrame(features)\n\n    demo_df = demo_df.to_pandas()\n    return feature_df.merge(demo_df, on=\"subject\", how=\"left\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-04T09:04:33.316564Z","iopub.execute_input":"2025-08-04T09:04:33.316876Z","iopub.status.idle":"2025-08-04T09:04:33.350937Z","shell.execute_reply.started":"2025-08-04T09:04:33.316848Z","shell.execute_reply":"2025-08-04T09:04:33.349752Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def add_gesture_id(sequence_df, process_df):\n    gestureIds = []\n    for seq_id, group in tqdm(sequence_df.group_by(\"sequence_id\")):\n        if group[\"gesture_id\"].n_unique() > 1:\n            print(\"Warning: Duplicate `gesture_id` detected! The same `sequence_id` cannot have multiple `gesture_id`.\")\n        gesture_id = group[\"gesture_id\"].first()\n        gestureIds.append({\n            \"sequence_id\": seq_id[0],\n            \"gesture_id\": gesture_id\n        })\n        \n    gestureId_df = pd.DataFrame(gestureIds)\n    \n    return process_df.merge(gestureId_df, on=\"sequence_id\", how=\"left\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-04T09:04:33.352194Z","iopub.execute_input":"2025-08-04T09:04:33.352535Z","iopub.status.idle":"2025-08-04T09:04:33.366449Z","shell.execute_reply.started":"2025-08-04T09:04:33.352502Z","shell.execute_reply":"2025-08-04T09:04:33.365355Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_process_df = data_process(train_df, train_demo_df)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-04T09:04:33.367542Z","iopub.execute_input":"2025-08-04T09:04:33.367904Z","iopub.status.idle":"2025-08-04T09:20:09.709134Z","shell.execute_reply.started":"2025-08-04T09:04:33.367871Z","shell.execute_reply":"2025-08-04T09:20:09.708163Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_process_df = add_gesture_id(train_df, train_process_df)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-04T09:20:09.710289Z","iopub.execute_input":"2025-08-04T09:20:09.710577Z","iopub.status.idle":"2025-08-04T09:20:15.767699Z","shell.execute_reply.started":"2025-08-04T09:20:09.710553Z","shell.execute_reply":"2025-08-04T09:20:15.766470Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_process_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-04T09:20:15.770667Z","iopub.execute_input":"2025-08-04T09:20:15.770935Z","iopub.status.idle":"2025-08-04T09:20:15.805461Z","shell.execute_reply.started":"2025-08-04T09:20:15.770913Z","shell.execute_reply":"2025-08-04T09:20:15.804490Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X = train_process_df.drop([\"sequence_id\", \"subject\", \"gesture_id\"], axis=1)\ny = train_process_df[\"gesture_id\"]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-04T09:20:15.806456Z","iopub.execute_input":"2025-08-04T09:20:15.806718Z","iopub.status.idle":"2025-08-04T09:20:15.860525Z","shell.execute_reply.started":"2025-08-04T09:20:15.806697Z","shell.execute_reply":"2025-08-04T09:20:15.859627Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.ensemble import RandomForestClassifier\n\nmodel = RandomForestClassifier(\n    n_estimators=300,\n    max_depth=None,\n    min_samples_split=2,\n    min_samples_leaf=1,\n    random_state=42,\n    n_jobs=-1\n)\nmodel.fit(X, y)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-04T09:20:15.861496Z","iopub.execute_input":"2025-08-04T09:20:15.861745Z","iopub.status.idle":"2025-08-04T09:20:45.960681Z","shell.execute_reply.started":"2025-08-04T09:20:15.861725Z","shell.execute_reply":"2025-08-04T09:20:45.959799Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_score = model.score(X, y)\nprint(f\"Training Accuracy: {train_score:.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-04T09:20:45.961733Z","iopub.execute_input":"2025-08-04T09:20:45.962658Z","iopub.status.idle":"2025-08-04T09:20:46.604634Z","shell.execute_reply.started":"2025-08-04T09:20:45.962627Z","shell.execute_reply":"2025-08-04T09:20:46.603724Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.model_selection import cross_val_score, StratifiedKFold\n\ncv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)\ncv_scores = cross_val_score(model, X, y, cv=cv, scoring=\"accuracy\", n_jobs=-1)\nprint(f\"Cross-Validation Accuracy: {cv_scores.mean():.4f} (±{cv_scores.std():.4f})\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-04T09:20:46.605526Z","iopub.execute_input":"2025-08-04T09:20:46.605824Z","iopub.status.idle":"2025-08-04T09:22:44.931619Z","shell.execute_reply.started":"2025-08-04T09:20:46.605791Z","shell.execute_reply":"2025-08-04T09:22:44.930784Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pickle\n\nwith open('random_forest_model.pkl', 'wb') as f:\n    pickle.dump(model, f)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-04T09:55:54.709669Z","iopub.execute_input":"2025-08-04T09:55:54.710086Z","iopub.status.idle":"2025-08-04T09:55:55.705173Z","shell.execute_reply.started":"2025-08-04T09:55:54.710047Z","shell.execute_reply":"2025-08-04T09:55:55.704124Z"}},"outputs":[],"execution_count":null}]}