{"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":"# Base on the Notebook \n# https://www.kaggle.com/code/jiaoyouzhang/cmi-2025-only-lightgbm","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-07T09:57:54.461414Z","iopub.execute_input":"2025-06-07T09:57:54.461735Z","iopub.status.idle":"2025-06-07T09:57:54.471201Z","shell.execute_reply.started":"2025-06-07T09:57:54.461703Z","shell.execute_reply":"2025-06-07T09:57:54.470017Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-07T09:57:54.473292Z","iopub.execute_input":"2025-06-07T09:57:54.473655Z","iopub.status.idle":"2025-06-07T09:57:57.194577Z","shell.execute_reply.started":"2025-06-07T09:57:54.473626Z","shell.execute_reply":"2025-06-07T09:57:57.193622Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import polars as pl\nfrom sklearn.preprocessing import LabelEncoder\nfrom sklearn.model_selection import StratifiedKFold, StratifiedShuffleSplit\nfrom sklearn.metrics import f1_score, classification_report\nimport lightgbm as lgb\nimport os\nimport warnings\nwarnings.filterwarnings('ignore')\n\n# Import evaluation API\nimport kaggle_evaluation.cmi_inference_server","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-07T09:57:57.195482Z","iopub.execute_input":"2025-06-07T09:57:57.195949Z","iopub.status.idle":"2025-06-07T09:58:07.229901Z","shell.execute_reply.started":"2025-06-07T09:57:57.195924Z","shell.execute_reply":"2025-06-07T09:58:07.228807Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load data\ntrain_df = pd.read_csv(\"/kaggle/input/cmi-detect-behavior-with-sensor-data/train.csv\")\ntest_df = pd.read_csv(\"/kaggle/input/cmi-detect-behavior-with-sensor-data/test.csv\")\ntest_demographics_df = pd.read_csv(\"/kaggle/input/cmi-detect-behavior-with-sensor-data/test_demographics.csv\")\ntrain_demographics_df = pd.read_csv(\"/kaggle/input/cmi-detect-behavior-with-sensor-data/train_demographics.csv\")\n\nprint(f\"Train shape: {train_df.shape}\")\nprint(f\"Test shape: {test_df.shape}\")","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-06-07T09:58:07.230971Z","iopub.execute_input":"2025-06-07T09:58:07.231738Z","iopub.status.idle":"2025-06-07T09:58:45.800681Z","shell.execute_reply.started":"2025-06-07T09:58:07.231701Z","shell.execute_reply":"2025-06-07T09:58:45.799727Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Filter to target sequences only (BFRB gestures)\ntrain_df = train_df.loc[train_df['sequence_type'] == 'Target'].reset_index(drop=True)\nprint(f\"Target sequences shape: {train_df.shape}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-07T09:58:45.801696Z","iopub.execute_input":"2025-06-07T09:58:45.801983Z","iopub.status.idle":"2025-06-07T09:58:46.727516Z","shell.execute_reply.started":"2025-06-07T09:58:45.801961Z","shell.execute_reply":"2025-06-07T09:58:46.725810Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Analyze gesture distribution\nprint(\"\\nGesture distribution:\")\nprint(train_df['gesture'].value_counts())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-07T09:58:46.729021Z","iopub.execute_input":"2025-06-07T09:58:46.729430Z","iopub.status.idle":"2025-06-07T09:58:46.768215Z","shell.execute_reply.started":"2025-06-07T09:58:46.729389Z","shell.execute_reply":"2025-06-07T09:58:46.766888Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Define sensor columns\nsensor_cols = ['acc_x', 'acc_y', 'acc_z', 'rot_w', 'rot_x', 'rot_y', 'rot_z']\nall_sensor_cols = [col for col in train_df.columns if any(s in col for s in ['acc_', 'rot_', 'thm_', 'tof_'])]\nprint(f\"\\nTotal sensor columns: {len(all_sensor_cols)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-07T09:58:46.772462Z","iopub.execute_input":"2025-06-07T09:58:46.772772Z","iopub.status.idle":"2025-06-07T09:58:46.792449Z","shell.execute_reply.started":"2025-06-07T09:58:46.772739Z","shell.execute_reply":"2025-06-07T09:58:46.790609Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"le = LabelEncoder()\ntrain_df['target'] = le.fit_transform(train_df['gesture'])\nprint(f\"\\nEncoded gestures: {len(le.classes_)} classes\")\nprint(\"Classes:\", le.classes_)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-07T09:58:46.793270Z","iopub.execute_input":"2025-06-07T09:58:46.793617Z","iopub.status.idle":"2025-06-07T09:58:46.880170Z","shell.execute_reply.started":"2025-06-07T09:58:46.793583Z","shell.execute_reply":"2025-06-07T09:58:46.879042Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def create_features(df, demographic_df):\n\n    # Create summary dataframe\n    df=df.copy()\n    summary = (df.groupby(['subject','sequence_id'])[sensor_cols].agg(['mean', 'std', 'min', 'max']))\n    summary.columns = ['_'.join(col).strip() for col in summary.columns.values]\n    summary = summary.reset_index()\n    #print( summary.shape)\n    \n    df_1 = summary.merge(demographic_df, on=\"subject\", how=\"left\")\n    #print(df_1.shape)\n    return df_1   ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-07T10:00:42.534249Z","iopub.execute_input":"2025-06-07T10:00:42.535251Z","iopub.status.idle":"2025-06-07T10:00:42.545505Z","shell.execute_reply.started":"2025-06-07T10:00:42.535213Z","shell.execute_reply":"2025-06-07T10:00:42.544444Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_features_df = create_features(train_df, train_demographics_df)\ntrain_info_df = train_df[['subject', 'sequence_id', 'target']].drop_duplicates()\n#print(train_info_df.shape)\ntrain_input_df= train_features_df.merge(train_info_df , on=['subject', 'sequence_id'], how='left')\n#print(train_input_df.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-07T09:59:23.645728Z","iopub.execute_input":"2025-06-07T09:59:23.645996Z","iopub.status.idle":"2025-06-07T09:59:24.233079Z","shell.execute_reply.started":"2025-06-07T09:59:23.645978Z","shell.execute_reply":"2025-06-07T09:59:24.232061Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_features_df = create_features(test_df, test_demographics_df)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-07T09:59:24.234644Z","iopub.execute_input":"2025-06-07T09:59:24.234952Z","iopub.status.idle":"2025-06-07T09:59:24.256745Z","shell.execute_reply.started":"2025-06-07T09:59:24.234931Z","shell.execute_reply":"2025-06-07T09:59:24.255672Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Prepare features and target\nfeature_cols = [col for col in train_input_df.columns \n                if col not in ['sequence_id', 'target', 'gesture', 'subject']]\nX = train_input_df[feature_cols].fillna(-1)\ny = train_input_df['target']\n\nprint(f\"Feature matrix shape: {X.shape}\")\nprint(f\"Target shape: {y.shape}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-07T09:59:24.257570Z","iopub.execute_input":"2025-06-07T09:59:24.257796Z","iopub.status.idle":"2025-06-07T09:59:24.284750Z","shell.execute_reply.started":"2025-06-07T09:59:24.257780Z","shell.execute_reply":"2025-06-07T09:59:24.283785Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def competition_metric(y_true, y_pred, le_instance, all_original_gestures):\n    \"\"\"\n    Competition metric calculation\n    \"\"\"\n    bfrb_gestures = [g for g in all_original_gestures if g in le_instance.classes_]\n    \n    # Binary F1: All are Target in this filtered dataset\n    y_true_binary = np.ones_like(y_true, dtype=int)\n    y_pred_binary = np.ones_like(y_pred, dtype=int)\n    binary_f1 = f1_score(y_true_binary, y_pred_binary, average='binary', pos_label=1, zero_division=0)\n    \n    # Macro F1: specific gesture classification\n    macro_f1 = f1_score(y_true, y_pred, average='macro', zero_division=0)\n    \n    final_score = (binary_f1 + macro_f1) / 2\n    return final_score, binary_f1, macro_f1","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-07T09:59:24.287368Z","iopub.execute_input":"2025-06-07T09:59:24.287806Z","iopub.status.idle":"2025-06-07T09:59:24.302913Z","shell.execute_reply.started":"2025-06-07T09:59:24.287778Z","shell.execute_reply":"2025-06-07T09:59:24.301800Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cross-validation setup\nprint(\"\\nSetting up cross-validation...\")\ncv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)\ncv_scores = []\nmodels = []\n\nall_original_gestures_in_train = train_df['gesture'].unique()\n\ncallbacks = [lgb.early_stopping(stopping_rounds=100, verbose=100)]\n\n# LightGBM model with cross-validation\nprint(\"\\nTraining LightGBM models with cross-validation...\")\nfor fold, (train_idx, val_idx) in enumerate(cv.split(X, y)):\n    print(f\"\\nFold {fold + 1}/5\")\n    \n    X_train_fold, X_val_fold = X.iloc[train_idx], X.iloc[val_idx]\n    y_train_fold, y_val_fold = y.iloc[train_idx], y.iloc[val_idx]\n    \n    # LightGBM model with GPU acceleration\n    model = lgb.LGBMClassifier(\n        objective='multiclass',\n        n_estimators= 1000,\n        learning_rate= 0.08,\n        max_depth= 15,\n        reg_alpha= 0.8,\n        lambda_l2= 4.0,  \n        num_leaves=31, \n        min_child_samples= 32,\n        colsample_bytree= 0.3,\n        subsample= 0.5,\n        subsample_freq=0,\n        cat_smooth=30.0,\n        is_unbalance=True,\n        max_bin=127,\n        verbose=-1,  \n        metric='multi_logloss',   \n        #device='gpu',  \n    )\n    \n    # Train model with verbose output\n    model.fit(\n        X_train_fold, y_train_fold,\n        eval_set=[(X_val_fold, y_val_fold)],  \n        eval_metric='multi_logloss',  \n        callbacks=callbacks\n    )\n    \n    # Predict\n    y_pred_fold = model.predict(X_val_fold)\n    \n    # Calculate score\n    score, binary_f1, macro_f1 = competition_metric(\n        y_val_fold, y_pred_fold, le, all_original_gestures_in_train\n    )\n    \n    cv_scores.append(score)\n    models.append(model)\n    \n    print(f\"Fold {fold + 1} - Competition Score: {score:.4f} (Binary F1: {binary_f1:.4f}, Macro F1: {macro_f1:.4f})\")\n\nprint(f\"\\nCross-validation results:\")\nprint(f\"Mean CV Score: {np.mean(cv_scores):.4f} (+/- {np.std(cv_scores) * 2:.4f})\")\nprint(f\"Individual fold scores: {cv_scores}\")\n\n# Train final model on all data with GPU acceleration\nprint(\"\\nTraining final model on all training data...\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-07T09:59:24.303626Z","iopub.execute_input":"2025-06-07T09:59:24.303867Z","iopub.status.idle":"2025-06-07T09:59:36.495197Z","shell.execute_reply.started":"2025-06-07T09:59:24.303850Z","shell.execute_reply":"2025-06-07T09:59:36.494290Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Prediction function for submission\ndef predict(sequence: pl.DataFrame, demographics: pl.DataFrame) -> str:\n    \"\"\"\n    Prediction function for Kaggle evaluation\n    \"\"\"\n    try:\n        # Convert to pandas\n        sequence_pd = sequence.to_pandas()\n        demographics_pd = demographics.to_pandas()\n        \n        # Create features for this single sequence\n        seq_features = create_features(sequence_pd, demographics_pd)\n\n        # Prepare feature vector - ensure all expected features are present\n        X_inference = seq_features[feature_cols].fillna(-1)\n        \n        # Predict using ensemble of CV models\n        predictions = []\n        for model in models:\n            pred = model.predict(X_inference)\n            # Ensure we get a scalar value\n            if isinstance(pred, np.ndarray):\n                pred = pred[0]\n            predictions.append(int(pred))\n        \n        # Use majority vote or most confident prediction\n        predicted_label_id = max(set(predictions), key=predictions.count)\n        \n        # Convert back to gesture string\n        predicted_gesture_str = le.inverse_transform([predicted_label_id])[0]\n        \n        return predicted_gesture_str\n        \n    except Exception as e:\n        print(f\"Error in prediction: {e}\")\n        # Return a default gesture if prediction fails\n        return le.classes_[0]\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-07T09:59:36.496129Z","iopub.execute_input":"2025-06-07T09:59:36.496449Z","iopub.status.idle":"2025-06-07T09:59:36.504127Z","shell.execute_reply.started":"2025-06-07T09:59:36.496427Z","shell.execute_reply":"2025-06-07T09:59:36.503046Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n# Test the prediction function\nprint(\"\\nTesting prediction function...\")\nsample_sequence = train_df[train_df['sequence_id'] == train_df['sequence_id'].iloc[0]]\nsample_demographics = train_demographics_df[train_demographics_df['subject'] == sample_sequence['subject'].iloc[0]]\n\nsample_seq_pl = pl.from_pandas(sample_sequence)\nsample_demo_pl = pl.from_pandas(sample_demographics)\n\ntest_prediction = predict(sample_seq_pl, sample_demo_pl)\nactual_gesture = sample_sequence['gesture'].iloc[0]\nprint(f\"Test prediction: {test_prediction}\")\nprint(f\"Actual gesture: {actual_gesture}\")\nprint(f\"Match: {test_prediction == actual_gesture}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-07T09:59:36.505050Z","iopub.execute_input":"2025-06-07T09:59:36.505299Z","iopub.status.idle":"2025-06-07T09:59:36.724949Z","shell.execute_reply.started":"2025-06-07T09:59:36.505281Z","shell.execute_reply":"2025-06-07T09:59:36.724018Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_sequence =  pl.read_csv(\"/kaggle/input/cmi-detect-behavior-with-sensor-data/test.csv\")\ntest_demographics=  pl.read_csv(\"/kaggle/input/cmi-detect-behavior-with-sensor-data/test_demographics.csv\")\n\ntest_prediction = predict(test_sequence, test_demographics)\nprint(f\"Test prediction: {test_prediction}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-07T09:59:36.725947Z","iopub.execute_input":"2025-06-07T09:59:36.726201Z","iopub.status.idle":"2025-06-07T09:59:36.858615Z","shell.execute_reply.started":"2025-06-07T09:59:36.726182Z","shell.execute_reply":"2025-06-07T09:59:36.857683Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Setup inference server\nprint(\"\\nSetting up inference server...\")\ninference_server = kaggle_evaluation.cmi_inference_server.CMIInferenceServer(predict)\n\nif os.getenv('KAGGLE_IS_COMPETITION_RERUN'):\n    inference_server.serve()\nelse:\n    inference_server.run_local_gateway(\n        data_paths=(\n            '/kaggle/input/cmi-detect-behavior-with-sensor-data/test.csv',\n            '/kaggle/input/cmi-detect-behavior-with-sensor-data/test_demographics.csv',\n        )\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-07T09:59:36.859498Z","iopub.execute_input":"2025-06-07T09:59:36.859845Z","iopub.status.idle":"2025-06-07T09:59:38.118286Z","shell.execute_reply.started":"2025-06-07T09:59:36.859818Z","shell.execute_reply":"2025-06-07T09:59:38.117410Z"}},"outputs":[],"execution_count":null}]}