{"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":"import numpy as np\nimport pandas as pd\nimport polars as pl\nfrom sklearn.preprocessing import LabelEncoder\nfrom sklearn.ensemble import RandomForestClassifier\nfrom sklearn.model_selection import StratifiedShuffleSplit\nfrom sklearn.metrics import f1_score\nfrom collections import Counter\nimport os\n\nimport kaggle_evaluation.cmi_inference_server","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-05-30T17:22:49.526259Z","iopub.execute_input":"2025-05-30T17:22:49.526577Z","iopub.status.idle":"2025-05-30T17:22:49.531733Z","shell.execute_reply.started":"2025-05-30T17:22:49.526548Z","shell.execute_reply":"2025-05-30T17:22:49.530962Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_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\")\n\ntrain_df = train_df.loc[train_df['sequence_type'] == 'Target'].reset_index(drop = True)\n\nsensor_cols = ['acc_x', 'acc_y', 'acc_z', 'rot_w', 'rot_x', 'rot_y', 'rot_z']\n\nall_sensor_cols = [col for col in train_df.columns if any(s in col for s in ['acc_', 'rot_', 'thm_', 'tof_'])]\n\n\ntrain_df[all_sensor_cols] = train_df[all_sensor_cols].fillna(-1)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T17:22:49.761989Z","iopub.execute_input":"2025-05-30T17:22:49.762308Z","iopub.status.idle":"2025-05-30T17:23:16.158142Z","shell.execute_reply.started":"2025-05-30T17:22:49.762285Z","shell.execute_reply":"2025-05-30T17:23:16.157077Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"le = LabelEncoder()\ntrain_df['encoded_gesture'] = le.fit_transform(train_df['gesture'])\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T17:23:16.159494Z","iopub.execute_input":"2025-05-30T17:23:16.159855Z","iopub.status.idle":"2025-05-30T17:23:16.231545Z","shell.execute_reply.started":"2025-05-30T17:23:16.159830Z","shell.execute_reply":"2025-05-30T17:23:16.230583Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def competition_metric(y_true, y_pred, le_instance, all_original_gestures):\n    bfrb_gestures = [g for g in all_original_gestures if g in le_instance.classes_]\n    \n    # Binary F1: assuming 'Target' is 1, 'Non-Target' is 0\n    # Since we only trained on 'Target', our model will always predict a BFRB gesture.\n    # Therefore, y_pred_binary will effectively always be 1 for a model trained this way.\n    # This metric part might be misleading on a validation set that only contains 'Target' gestures.\n    # For a proper binary F1, the true labels would need to include non-BFRB types.\n    y_true_binary = np.ones_like(y_true, dtype=int) # All are 'Target' in this filtered dataset\n    y_pred_binary = np.ones_like(y_pred, dtype=int) # Model predicts only BFRB if trained on 'Target'\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    # This is calculated only over the BFRB gestures.\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\n\nunique_sequences = train_df[['sequence_id', 'encoded_gesture']].drop_duplicates()\nunique_sequence_ids = unique_sequences['sequence_id']\nunique_sequence_targets = unique_sequences['encoded_gesture']\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T17:23:16.232592Z","iopub.execute_input":"2025-05-30T17:23:16.232924Z","iopub.status.idle":"2025-05-30T17:23:16.285171Z","shell.execute_reply.started":"2025-05-30T17:23:16.232895Z","shell.execute_reply":"2025-05-30T17:23:16.284028Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"splitter = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=42)\nfor train_idx, val_idx in splitter.split(unique_sequence_ids, unique_sequence_targets):\n    train_seq_ids = unique_sequence_ids.iloc[train_idx]\n    val_seq_ids = unique_sequence_ids.iloc[val_idx]\n\nX_train_df = train_df[train_df['sequence_id'].isin(train_seq_ids)]\nX_val_df = train_df[train_df['sequence_id'].isin(val_seq_ids)]\n\ny_train = X_train_df['encoded_gesture']\ny_val = X_val_df['encoded_gesture']\n\nX_train = X_train_df[sensor_cols]\nX_val = X_val_df[sensor_cols]\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T17:24:41.248515Z","iopub.execute_input":"2025-05-30T17:24:41.248866Z","iopub.status.idle":"2025-05-30T17:24:41.646371Z","shell.execute_reply.started":"2025-05-30T17:24:41.248842Z","shell.execute_reply":"2025-05-30T17:24:41.645584Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from lightgbm import LGBMClassifier\n\n# Initialize LightGBM model for multiclass classification\nlgbm_model = LGBMClassifier(\n    objective='multiclass',\n    n_estimators=1500,\n    max_depth=7,\n    random_state=42,\n    n_jobs=-1,\n    num_class=len(np.unique(y_train))  # Needed for multiclass\n)\n\n# Fit the model\nlgbm_model.fit(X_train, y_train)\n\n# Predict on validation set\ny_val_pred = lgbm_model.predict(X_val)\n\n# Evaluation\nall_original_gestures_in_train = train_df['gesture'].unique()\nvalidation_score = competition_metric(y_val, y_val_pred, le, all_original_gestures_in_train)\nprint(f\"Validation Score: {validation_score:.4f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T17:24:41.647748Z","iopub.execute_input":"2025-05-30T17:24:41.648035Z","iopub.status.idle":"2025-05-30T17:26:05.754351Z","shell.execute_reply.started":"2025-05-30T17:24:41.648006Z","shell.execute_reply":"2025-05-30T17:26:05.753446Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def predict(sequence: pl.DataFrame, demographics: pl.DataFrame) -> str:\n    sequence_pd = sequence.to_pandas()\n    sequence_pd[all_sensor_cols] = sequence_pd[all_sensor_cols].fillna(-1)\n    X_inference = sequence_pd[sensor_cols]\n    \n    # Get predictions for all rows in the sequence\n    all_predicted_label_ids = lgbm_model.predict(X_inference)\n    \n    # Find the most common predicted label ID\n    # Counter returns a list of (element, count) tuples, sorted by count.\n    # We want the element of the first tuple.\n    most_common_label_id = Counter(all_predicted_label_ids).most_common(1)[0][0]\n    \n    # Convert the most common numerical label back to the original gesture string\n    predicted_gesture_str = le.inverse_transform([most_common_label_id])[0]\n    \n    return predicted_gesture_str","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T17:26:11.679036Z","iopub.execute_input":"2025-05-30T17:26:11.679650Z","iopub.status.idle":"2025-05-30T17:26:11.685472Z","shell.execute_reply.started":"2025-05-30T17:26:11.679624Z","shell.execute_reply":"2025-05-30T17:26:11.684486Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"inference_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    )\n\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T17:26:11.955194Z","iopub.execute_input":"2025-05-30T17:26:11.955706Z","iopub.status.idle":"2025-05-30T17:26:13.570755Z","shell.execute_reply.started":"2025-05-30T17:26:11.955672Z","shell.execute_reply":"2025-05-30T17:26:13.569820Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}