{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","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":31040,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# === IMPORTS ===\nimport pandas as pd\nimport numpy as np\nimport lightgbm as lgb\nimport pickle\nfrom sklearn.model_selection import StratifiedKFold\nfrom sklearn.preprocessing import LabelEncoder\nfrom sklearn.metrics import f1_score\nimport polars as pl\nimport os\n\n# === LOAD DATA ===\ntrain = pd.read_csv(\"/kaggle/input/cmi-detect-behavior-with-sensor-data/train.csv\")\ndemographics = pd.read_csv(\"/kaggle/input/cmi-detect-behavior-with-sensor-data/train_demographics.csv\")\n\n# === FEATURE EXTRACTION FUNCTION ===\ndef extract_features(group, demo_df):\n    df = group.copy()\n    sequence_id = df['sequence_id'].iloc[0]\n    demo = demo_df.loc[demo_df['subject'] == df['subject'].iloc[0]].iloc[0]\n    row = {'sequence_id': sequence_id}\n\n    for col in [\"acc_x\", \"acc_y\", \"acc_z\", \"rot_w\", \"rot_x\", \"rot_y\", \"rot_z\"]:\n        row[f\"{col}_mean\"] = df[col].mean()\n        row[f\"{col}_std\"] = df[col].std()\n        row[f\"{col}_min\"] = df[col].min()\n        row[f\"{col}_max\"] = df[col].max()\n\n    for col in [c for c in df.columns if c.startswith(\"thm_\")]:\n        row[f\"{col}_mean\"] = df[col].mean()\n        row[f\"{col}_std\"] = df[col].std()\n\n    for tof_prefix in range(1, 6):\n        tof_cols = [f\"tof_{tof_prefix}_v{i}\" for i in range(64) if f\"tof_{tof_prefix}_v{i}\" in df.columns]\n        if len(tof_cols) > 0:\n            tof_data = df[tof_cols].replace(-1, np.nan)\n            row[f\"tof_{tof_prefix}_mean\"] = tof_data.mean(axis=1).mean()\n            row[f\"tof_{tof_prefix}_std\"] = tof_data.std(axis=1).mean()\n\n    for col in ['age', 'sex', 'handedness', 'adult_child', 'height_cm', 'shoulder_to_wrist_cm', 'elbow_to_wrist_cm']:\n        row[col] = demo[col] if col in demo else np.nan\n\n    return pd.Series(row)\n\n# === APPLY FEATURE EXTRACTION ===\nfeatures_df = train.groupby(\"sequence_id\").apply(lambda x: extract_features(x, demographics)).reset_index(drop=True)\n\n# === ADD TARGET COLUMN ===\ntargets = train.groupby(\"sequence_id\")[\"gesture\"].first().reset_index()\nfeatures_df = features_df.merge(targets, on=\"sequence_id\", how=\"left\")\n\n# === ENCODE TARGET LABEL ===\nle = LabelEncoder()\nfeatures_df[\"gesture_encoded\"] = le.fit_transform(features_df[\"gesture\"])\n\n# === SAVE ENCODER ===\nwith open(\"label_encoder.pkl\", \"wb\") as f:\n    pickle.dump(le, f)\n\n# === MODEL TRAINING ===\nX = features_df.drop(columns=[\"sequence_id\", \"gesture\", \"gesture_encoded\"])\ny = features_df[\"gesture_encoded\"]\n\n# Save feature column names\nwith open(\"feature_columns.pkl\", \"wb\") as f:\n    pickle.dump(X.columns.tolist(), f)\n\n# Use Stratified K-Fold\nskf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)\n\nf1_scores = []\n\nfor fold, (train_idx, val_idx) in enumerate(skf.split(X, y), 1):\n    X_train, X_val = X.iloc[train_idx], X.iloc[val_idx]\n    y_train, y_val = y.iloc[train_idx], y.iloc[val_idx]\n\n    model = lgb.LGBMClassifier(n_estimators=300, random_state=42)\n    model.fit(X_train, y_train)\n\n    preds = model.predict(X_val)\n    f1 = f1_score(y_val, preds, average='macro')\n    print(f\"Fold {fold} Macro F1: {f1:.4f}\")\n    f1_scores.append(f1)\n\nprint(f\"\\nAverage Macro F1: {np.mean(f1_scores):.4f}\")\n\n# === SAVE FINAL MODEL ===\nmodel.fit(X, y)\nwith open(\"model.pkl\", \"wb\") as f:\n    pickle.dump(model, f)\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-06-23T19:24:13.584455Z","iopub.execute_input":"2025-06-23T19:24:13.585620Z","iopub.status.idle":"2025-06-23T19:28:41.116329Z","shell.execute_reply.started":"2025-06-23T19:24:13.585588Z","shell.execute_reply":"2025-06-23T19:28:41.114777Z"}},"outputs":[],"execution_count":null}]}