{"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"},{"sourceId":13568292,"sourceType":"datasetVersion","datasetId":8619185}],"dockerImageVersionId":31153,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nfrom sklearn.preprocessing import LabelEncoder\nfrom sklearn.model_selection import StratifiedKFold\nfrom sklearn.metrics import f1_score\nimport lightgbm as lgb\nimport warnings\n\nwarnings.filterwarnings('ignore')\n\n# --- Load All 4 Data Files ---\ntry:\n    # Main sensor data\n    train_df = pd.read_csv('/kaggle/input/cmi-data-set/train.csv')\n    test_df = pd.read_csv('/kaggle/input/cmi-data-set/test.csv')\n    \n    # Demographics files\n    train_demo_df = pd.read_csv('/kaggle/input/cmi-data-set/train_demographics.csv')\n    test_demo_df = pd.read_csv('/kaggle/input/cmi-data-set/test_demographics.csv') # Corrected typo\n\n    print(\"All 4 CSV files loaded successfully.\")\n\nexcept FileNotFoundError:\n    print(\"One or more CSV files not found. Please check file paths.\")\n    \nprint(f\"Train shape: {train_df.shape}\")\nprint(f\"Test shape: {test_df.shape}\")\nprint(f\"Train Demographics shape: {train_demo_df.shape}\")\nprint(f\"Test Demographics shape: {test_demo_df.shape}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-31T15:19:07.963428Z","iopub.execute_input":"2025-10-31T15:19:07.963716Z","iopub.status.idle":"2025-10-31T15:19:46.767298Z","shell.execute_reply.started":"2025-10-31T15:19:07.963691Z","shell.execute_reply":"2025-10-31T15:19:46.766310Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"Extracting labels from train.csv...\")\n\n# Create the labels_df by taking the unique sequence_id and gesture pairs\nlabels_df = train_df[['sequence_id', 'gesture']].drop_duplicates().reset_index(drop=True)\n\nprint(f\"Labels extracted. Found {len(labels_df)} unique sequences.\")\nprint(labels_df.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-31T15:19:51.388168Z","iopub.execute_input":"2025-10-31T15:19:51.388696Z","iopub.status.idle":"2025-10-31T15:19:51.500908Z","shell.execute_reply.started":"2025-10-31T15:19:51.388673Z","shell.execute_reply":"2025-10-31T15:19:51.500167Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def create_features(df):\n    # 'gesture' is already in metadata_cols, so it will be ignored correctly\n    metadata_cols = ['row_id', 'sequence_id', 'sequence_counter', 'subject', \n                     'orientation', 'behavior', 'phase', 'gesture', 'sequence_type']\n    \n    sensor_cols = [col for col in df.columns if col not in metadata_cols]\n    \n    agg_funcs = ['mean', 'std', 'min', 'max', 'median']\n    \n    print(f\"Starting sensor feature engineering with {len(sensor_cols)} columns...\")\n    \n    df[sensor_cols] = df[sensor_cols].apply(pd.to_numeric, errors='coerce')\n    df[sensor_cols] = df[sensor_cols].fillna(0) \n\n    grouped_df = df.groupby('sequence_id')[sensor_cols].agg(agg_funcs)\n    \n    new_cols = []\n    for col in grouped_df.columns:\n        new_cols.append(f\"{col[0]}_{col[1]}\")\n    grouped_df.columns = new_cols\n    \n    print(\"Sensor feature engineering complete.\")\n    return grouped_df.reset_index()\n\n# Create sensor features for train and test data\nX_train_sensor_features = create_features(train_df)\nX_test_sensor_features = create_features(test_df)\n\nprint(f\"Train sensor features shape: {X_train_sensor_features.shape}\")\nprint(f\"Test sensor features shape: {X_test_sensor_features.shape}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-31T15:19:54.853519Z","iopub.execute_input":"2025-10-31T15:19:54.853962Z","iopub.status.idle":"2025-10-31T15:20:11.737322Z","shell.execute_reply.started":"2025-10-31T15:19:54.853931Z","shell.execute_reply":"2025-10-31T15:20:11.736542Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"Starting demographic feature processing...\")\n\n# --- Handle Categorical Demo Features ---\ncategorical_cols = ['adult_child', 'sex', 'handedness']\n\ntrain_demo_df['is_train'] = 1\ntest_demo_df['is_train'] = 0\ncombined_demo_df = pd.concat([train_demo_df, test_demo_df], ignore_index=True)\ncombined_demo_df = pd.get_dummies(combined_demo_df, columns=categorical_cols, drop_first=True)\n\ntrain_demo_processed = combined_demo_df[combined_demo_df['is_train'] == 1].drop(columns=['is_train'])\ntest_demo_processed = combined_demo_df[combined_demo_df['is_train'] == 0].drop(columns=['is_train'])\n\n# --- Get subject mapping from main files ---\nsubject_map_train = train_df[['sequence_id', 'subject']].drop_duplicates()\nsubject_map_test = test_df[['sequence_id', 'subject']].drop_duplicates()\n\n# --- Merge Demo Features with Sensor Features ---\nX_train_features = pd.merge(X_train_sensor_features, subject_map_train, on='sequence_id')\nX_test_features = pd.merge(X_test_sensor_features, subject_map_test, on='sequence_id')\n\nX_train_features = pd.merge(X_train_features, train_demo_processed, on='subject', how='left')\nX_test_features = pd.merge(X_test_features, test_demo_processed, on='subject', how='left')\n\n# Fill NaNs\ndemo_feature_cols = [col for col in train_demo_processed.columns if col != 'subject']\nX_train_features[demo_feature_cols] = X_train_features[demo_feature_cols].fillna(X_train_features[demo_feature_cols].median())\nX_test_features[demo_feature_cols] = X_test_features[demo_feature_cols].fillna(X_train_features[demo_feature_cols].median()) \n\nprint(\"Demographic features merged.\")\nprint(f\"Final train features shape: {X_train_features.shape}\")\nprint(f\"Final test features shape: {X_test_features.shape}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-31T15:20:16.223377Z","iopub.execute_input":"2025-10-31T15:20:16.223980Z","iopub.status.idle":"2025-10-31T15:20:16.458219Z","shell.execute_reply.started":"2025-10-31T15:20:16.223952Z","shell.execute_reply":"2025-10-31T15:20:16.457536Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# --- Prepare Training Data (X and y) ---\n\n# Merge features with labels (from Step 2)\ntrain_data = pd.merge(labels_df[['sequence_id', 'gesture']], X_train_features, on='sequence_id', how='inner')\n\n# --- Label Encoding for the target 'gesture' ---\nle = LabelEncoder()\ntrain_data['gesture_encoded'] = le.fit_transform(train_data['gesture'])\n\n# Get the list of ALL feature columns\nfeature_columns = [\n    col for col in X_train_features.columns if col not in ['sequence_id', 'subject', 'gesture']\n]\n\n# Define our final X and y\nX = train_data[feature_columns]\ny = train_data['gesture_encoded']\n\n# Align test set columns\nX_test = X_test_features[feature_columns]\n\nprint(f\"Final X_train shape: {X.shape}\")\nprint(f\"Final y_train shape: {y.shape}\")\nprint(f\"Final X_test shape: {X_test.shape}\")\nprint(f\"Found {len(le.classes_)} unique gestures: {le.classes_}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-31T15:20:21.057847Z","iopub.execute_input":"2025-10-31T15:20:21.058425Z","iopub.status.idle":"2025-10-31T15:20:21.258252Z","shell.execute_reply.started":"2025-10-31T15:20:21.058399Z","shell.execute_reply":"2025-10-31T15:20:21.257481Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"\\n--- Step 6: Start Model Training (with Random Forest) ---\")\n\n# Import the new model\nfrom sklearn.ensemble import RandomForestClassifier\n\nN_CLASSES = len(le.classes_)\nN_SPLITS = 5\nskf = StratifiedKFold(n_splits=N_SPLITS, shuffle=True, random_state=42)\n\noof_preds = np.zeros((len(X), N_CLASSES)) \ntest_preds = np.zeros((len(X_test), N_CLASSES)) \nmodels = []\n\nfor fold, (train_index, val_index) in enumerate(skf.split(X, y)):\n    print(f\"--- Fold {fold+1}/{N_SPLITS} ---\")\n    X_train, X_val = X.iloc[train_index], X.iloc[val_index]\n    y_train, y_val = y.iloc[train_index], y.iloc[val_index]\n    \n    # Initialize Random Forest Classifier\n    model = RandomForestClassifier(\n        n_estimators=100,      \n        random_state=42,\n        n_jobs=-1,             \n        min_samples_leaf=5,    \n        class_weight='balanced'\n    )\n    \n    # Train the model\n    model.fit(X_train, y_train)\n    \n    # Store predictions\n    val_preds = model.predict_proba(X_val)\n    oof_preds[val_index] = val_preds\n    \n    # Predict on test set\n    test_preds += model.predict_proba(X_test) / N_SPLITS\n    models.append(model)\n    \n    # --- LOCAL SCORE CHECK ---\n    \n    # !! ==================== FIX IS HERE ==================== !!\n    # !! You MUST update this list with your competition's \"target\" gestures !!\n    # !! Use the output from print(list(le.classes_)) to see your options.\n    \n    TARGET_GESTURES = ['A', 'C', 'F'] # <--- EDIT THIS LINE (This is just an example)\n    \n    # !! ===================================================== !!\n    \n    \n    y_val_labels_pred = le.inverse_transform(np.argmax(val_preds, axis=1))\n    y_val_labels_true = le.inverse_transform(y_val)\n    \n    y_val_binary_pred = [1 if g in TARGET_GESTURES else 0 for g in y_val_labels_pred]\n    y_val_binary_true = [1 if g in TARGET_GESTURES else 0 for g in y_val_labels_true]\n    \n    y_val_macro_pred = [g if g in TARGET_GESTURES else 'non_target' for g in y_val_labels_pred]\n    y_val_macro_true = [g if g in TARGET_GESTURES else 'non_target' for g in y_val_labels_true]\n\n    binary_f1 = f1_score(y_val_binary_true, y_val_binary_pred, average='binary', zero_division=0)\n    macro_f1 = f1_score(y_val_macro_true, y_val_macro_pred, average='macro', zero_division=0)\n    final_score = (binary_f1 + macro_f1) / 2\n    \n    print(f\"Fold {fold+1} Binary F1: {binary_f1:.4f}\")\n    print(f\"Fold {fold+1} Macro F1: {macro_f1:.4f}\")\n    print(f\"Fold {fold+1} Final Score: {final_score:.4f}\")\n\nprint(\"\\n--- Training Complete ---\")\n\n\n# --- Step 7: Create Submission File (Unchanged) ---\nprint(\"\\n--- Step 7: Create Submission File ---\")\n\n# Get the class with the highest probability\nfinal_test_preds_encoded = np.argmax(test_preds, axis=1)\n\n# Decode the integer predictions back to string labels\nfinal_test_preds_labels = le.inverse_transform(final_test_preds_encoded)\n\n# Create the submission DataFrame\nsubmission_df = pd.DataFrame({\n    'sequence_id': X_test_features['sequence_id'],\n    'gesture': final_test_preds_labels\n})\n\n# Save the submission file\nsubmission_df.to_csv('submission.csv', index=False)\n\nprint(\"\\nSubmission file created successfully!\")\nprint(submission_df.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-31T15:47:27.081985Z","iopub.execute_input":"2025-10-31T15:47:27.082844Z","iopub.status.idle":"2025-10-31T15:47:55.020359Z","shell.execute_reply.started":"2025-10-31T15:47:27.082798Z","shell.execute_reply":"2025-10-31T15:47:55.019344Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}