{"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 os\n\nimport numpy as np\nimport pandas as pd\nimport polars as pl\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport kaggle_evaluation.cmi_inference_server\n\npd.set_option('display.max_columns', 100)\nsns.set(style=\"whitegrid\")\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:29:17.168639Z","iopub.execute_input":"2025-05-30T08:29:17.168901Z","iopub.status.idle":"2025-05-30T08:29:19.773427Z","shell.execute_reply.started":"2025-05-30T08:29:17.168875Z","shell.execute_reply":"2025-05-30T08:29:19.772544Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load file\ntrain_path = \"/kaggle/input/cmi-detect-behavior-with-sensor-data/train.csv\"\ntest_path = \"/kaggle/input/cmi-detect-behavior-with-sensor-data/test.csv\"\n\ntrain_demo_path = \"/kaggle/input/cmi-detect-behavior-with-sensor-data/train_demographics.csv\"\ntest_demo_path = \"/kaggle/input/cmi-detect-behavior-with-sensor-data/test_demographics.csv\"\n\n# Load dữ liệu\ntrain = pd.read_csv(train_path)\ntrain_demographics = pd.read_csv(train_demo_path)\ntest = pd.read_csv(test_path)\ntest_demographics = pd.read_csv(test_demo_path)\nprint(\"Train shape:\", train.shape)\nprint(\"Unique sequences:\", train['sequence_id'].nunique())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:29:19.774303Z","iopub.execute_input":"2025-05-30T08:29:19.774763Z","iopub.status.idle":"2025-05-30T08:29:53.855230Z","shell.execute_reply.started":"2025-05-30T08:29:19.774736Z","shell.execute_reply":"2025-05-30T08:29:53.854408Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Merge demographics\nmerge_demographics = pd.concat([train_demographics,test_demographics]).drop_duplicates().reset_index(drop=True)\nmerge_demographics","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:29:53.857407Z","iopub.execute_input":"2025-05-30T08:29:53.857729Z","iopub.status.idle":"2025-05-30T08:29:53.891686Z","shell.execute_reply.started":"2025-05-30T08:29:53.857701Z","shell.execute_reply":"2025-05-30T08:29:53.890946Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# columns only in train (not in test)\ndiff_cols = list(set(train.columns.to_list())-set(test.columns.to_list()))\ndiff_cols","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:29:53.892490Z","iopub.execute_input":"2025-05-30T08:29:53.892801Z","iopub.status.idle":"2025-05-30T08:29:53.898597Z","shell.execute_reply.started":"2025-05-30T08:29:53.892775Z","shell.execute_reply":"2025-05-30T08:29:53.897920Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"gesture_df = train[diff_cols].drop_duplicates().reset_index(drop=True)\ngesture_df.to_csv('gesture_dict.csv', index=False)\ngesture_df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:29:53.899440Z","iopub.execute_input":"2025-05-30T08:29:53.899755Z","iopub.status.idle":"2025-05-30T08:29:54.132243Z","shell.execute_reply.started":"2025-05-30T08:29:53.899734Z","shell.execute_reply":"2025-05-30T08:29:54.131446Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"gesture_df[gesture_df['sequence_type']=='Target'].gesture.value_counts()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:29:54.133116Z","iopub.execute_input":"2025-05-30T08:29:54.133393Z","iopub.status.idle":"2025-05-30T08:29:54.140470Z","shell.execute_reply.started":"2025-05-30T08:29:54.133372Z","shell.execute_reply":"2025-05-30T08:29:54.139880Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"gesture_df[gesture_df['sequence_type']=='Non-Target'].gesture.value_counts()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:29:54.141150Z","iopub.execute_input":"2025-05-30T08:29:54.141434Z","iopub.status.idle":"2025-05-30T08:29:54.159701Z","shell.execute_reply.started":"2025-05-30T08:29:54.141409Z","shell.execute_reply":"2025-05-30T08:29:54.158952Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# there are 4 stages of 1 gesture\ntrain.behavior.unique()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:29:54.160721Z","iopub.execute_input":"2025-05-30T08:29:54.160995Z","iopub.status.idle":"2025-05-30T08:29:54.216947Z","shell.execute_reply.started":"2025-05-30T08:29:54.160974Z","shell.execute_reply":"2025-05-30T08:29:54.216174Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# All gesture have the same 4 stages\npd.DataFrame(pd.DataFrame(train.groupby(['gesture', 'behavior']).size()).reset_index().gesture.value_counts())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:29:54.220228Z","iopub.execute_input":"2025-05-30T08:29:54.220492Z","iopub.status.idle":"2025-05-30T08:29:54.320362Z","shell.execute_reply.started":"2025-05-30T08:29:54.220471Z","shell.execute_reply":"2025-05-30T08:29:54.319702Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"target = ['gesture']\nmeta_features= ['row_id', 'sequence_type', 'sequence_id', 'sequence_counter', 'subject', 'orientation', 'behavior', 'phase']\nimu_sensor_features = ['acc_x', 'acc_y', 'acc_z', 'rot_w', 'rot_x', 'rot_y', 'rot_z',]\nthermo_features = ['thm_1', 'thm_2', 'thm_3', 'thm_4', 'thm_5',]\ntof_1_features = [f'tof_1_v{px}' for px in range(64)]\ntof_2_features = [f'tof_2_v{px}' for px in range(64)]\ntof_3_features = [f'tof_3_v{px}' for px in range(64)]\ntof_4_features = [f'tof_4_v{px}' for px in range(64)]\ntof_5_features = [f'tof_5_v{px}' for px in range(64)]\n\ntof_features = tof_1_features + tof_2_features + tof_3_features + tof_4_features + tof_5_features\nsensors_features = imu_sensor_features + thermo_features + tof_features\n\nall_features = meta_features + sensors_features\nlen(all_features+target)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:29:54.321066Z","iopub.execute_input":"2025-05-30T08:29:54.321286Z","iopub.status.idle":"2025-05-30T08:29:54.329602Z","shell.execute_reply.started":"2025-05-30T08:29:54.321270Z","shell.execute_reply":"2025-05-30T08:29:54.328967Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train.info()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:29:54.330362Z","iopub.execute_input":"2025-05-30T08:29:54.330583Z","iopub.status.idle":"2025-05-30T08:29:54.365262Z","shell.execute_reply.started":"2025-05-30T08:29:54.330565Z","shell.execute_reply":"2025-05-30T08:29:54.364607Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Check Missing data","metadata":{}},{"cell_type":"code","source":"def check_missing_df(df:pd.DataFrame,col:list)->pd.DataFrame:\n    missing_data = df[col].isnull().sum()\n    missing_pct = (missing_data / len(train)) * 100\n    missing_df = pd.DataFrame({'Missing_Count': missing_data, 'Missing_Percentage': missing_pct})\n    return missing_df[missing_df['Missing_Count'] > 0].sort_values('Missing_Count', ascending=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:29:54.366145Z","iopub.execute_input":"2025-05-30T08:29:54.366426Z","iopub.status.idle":"2025-05-30T08:29:54.381055Z","shell.execute_reply.started":"2025-05-30T08:29:54.366405Z","shell.execute_reply":"2025-05-30T08:29:54.380243Z"},"_kg_hide-input":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"check_missing_df(train, meta_features+target)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:29:54.381963Z","iopub.execute_input":"2025-05-30T08:29:54.382289Z","iopub.status.idle":"2025-05-30T08:29:54.678298Z","shell.execute_reply.started":"2025-05-30T08:29:54.382262Z","shell.execute_reply":"2025-05-30T08:29:54.677579Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"check_missing_df(train, imu_sensor_features)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:29:54.679048Z","iopub.execute_input":"2025-05-30T08:29:54.679275Z","iopub.status.idle":"2025-05-30T08:29:54.708350Z","shell.execute_reply.started":"2025-05-30T08:29:54.679256Z","shell.execute_reply":"2025-05-30T08:29:54.707588Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"check_missing_df(train, thermo_features)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:29:54.709153Z","iopub.execute_input":"2025-05-30T08:29:54.709450Z","iopub.status.idle":"2025-05-30T08:29:54.733481Z","shell.execute_reply.started":"2025-05-30T08:29:54.709411Z","shell.execute_reply":"2025-05-30T08:29:54.732708Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"check_missing_df(train, tof_1_features)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:29:54.734290Z","iopub.execute_input":"2025-05-30T08:29:54.734547Z","iopub.status.idle":"2025-05-30T08:29:54.950106Z","shell.execute_reply.started":"2025-05-30T08:29:54.734522Z","shell.execute_reply":"2025-05-30T08:29:54.949258Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"check_missing_df(train, tof_2_features)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:29:54.950926Z","iopub.execute_input":"2025-05-30T08:29:54.951258Z","iopub.status.idle":"2025-05-30T08:29:55.168466Z","shell.execute_reply.started":"2025-05-30T08:29:54.951233Z","shell.execute_reply":"2025-05-30T08:29:55.167539Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import missingno as msno\nmsno.matrix(train)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:29:55.169229Z","iopub.execute_input":"2025-05-30T08:29:55.169445Z","iopub.status.idle":"2025-05-30T08:30:43.037473Z","shell.execute_reply.started":"2025-05-30T08:29:55.169427Z","shell.execute_reply":"2025-05-30T08:30:43.033724Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"seem tof_5 missing missin more value than others","metadata":{}},{"cell_type":"markdown","source":"Seem alots feature need to preprocess before use","metadata":{}},{"cell_type":"code","source":"target = ['gesture']\nmeta_features= ['row_id', 'sequence_type', 'sequence_id', 'sequence_counter', 'subject', 'orientation', 'behavior', 'phase']\nimu_sensor_features = ['acc_x', 'acc_y', 'acc_z', 'rot_w', 'rot_x', 'rot_y', 'rot_z',]\nthermo_features = ['thm_1', 'thm_2', 'thm_3', 'thm_4', 'thm_5',]\ntof_1_features = [f'tof_1_v{px}' for px in range(64)]\ntof_2_features = [f'tof_2_v{px}' for px in range(64)]\ntof_3_features = [f'tof_3_v{px}' for px in range(64)]\ntof_4_features = [f'tof_4_v{px}' for px in range(64)]\ntof_5_features = [f'tof_5_v{px}' for px in range(64)]\n\ntof_features = tof_1_features + tof_2_features + tof_3_features + tof_4_features + tof_5_features\nsensors_features = imu_sensor_features + thermo_features + tof_features\n\nall_features = meta_features + sensors_features\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:30:43.049141Z","iopub.execute_input":"2025-05-30T08:30:43.050191Z","iopub.status.idle":"2025-05-30T08:30:43.078102Z","shell.execute_reply.started":"2025-05-30T08:30:43.050084Z","shell.execute_reply":"2025-05-30T08:30:43.075551Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train['tof_1_mean'] = train[tof_1_features].mean(axis=1)\ntrain['tof_2_mean'] = train[tof_2_features].mean(axis=1)\ntrain['tof_3_mean'] = train[tof_3_features].mean(axis=1)\ntrain['tof_4_mean'] = train[tof_4_features].mean(axis=1)\ntrain['tof_5_mean'] = train[tof_5_features].mean(axis=1)\n\ntof_means = ['tof_1_mean','tof_2_mean','tof_3_mean','tof_4_mean','tof_5_mean']\n\ncheck_ms_train = train[meta_features+imu_sensor_features+thermo_features+ tof_means]\n\ncheck_ms_train[check_ms_train.isnull().any(axis=1)]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:30:43.081584Z","iopub.execute_input":"2025-05-30T08:30:43.081918Z","iopub.status.idle":"2025-05-30T08:30:46.537464Z","shell.execute_reply.started":"2025-05-30T08:30:43.081895Z","shell.execute_reply":"2025-05-30T08:30:46.536567Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"msno.matrix(check_ms_train)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:30:46.538572Z","iopub.execute_input":"2025-05-30T08:30:46.538867Z","iopub.status.idle":"2025-05-30T08:30:54.914522Z","shell.execute_reply.started":"2025-05-30T08:30:46.538839Z","shell.execute_reply":"2025-05-30T08:30:54.913509Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"msno.dendrogram(check_ms_train)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:30:54.915530Z","iopub.execute_input":"2025-05-30T08:30:54.915813Z","iopub.status.idle":"2025-05-30T08:30:55.863869Z","shell.execute_reply.started":"2025-05-30T08:30:54.915792Z","shell.execute_reply":"2025-05-30T08:30:55.863066Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"🔍 **Insights from Dendrogram**\n\n* **`tof_*_mean` and `thm_*` features** cluster tightly → often missing together → likely from same sensor group.\n* **`rot_*` and `acc_*` features** form a separate cluster → different missing pattern → motion-related sensors.\n* **Meta columns** (`row_id`, `sequence_id`, etc.) are separate → little or no missingness.\n* Two main missingness patterns: `TOF/thermal` vs. `motion/meta data`.\n","metadata":{}},{"cell_type":"markdown","source":"# Overview statistic Data","metadata":{}},{"cell_type":"code","source":"train[imu_sensor_features].describe().T","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:30:55.865002Z","iopub.execute_input":"2025-05-30T08:30:55.866104Z","iopub.status.idle":"2025-05-30T08:30:56.060402Z","shell.execute_reply.started":"2025-05-30T08:30:55.866075Z","shell.execute_reply":"2025-05-30T08:30:56.059681Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train[thermo_features].describe().T","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:30:56.061261Z","iopub.execute_input":"2025-05-30T08:30:56.061498Z","iopub.status.idle":"2025-05-30T08:30:56.210386Z","shell.execute_reply.started":"2025-05-30T08:30:56.061479Z","shell.execute_reply":"2025-05-30T08:30:56.209646Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# tof_features = tof_1_features + tof_2_features + tof_3_features + tof_4_features + tof_5_features\ntrain[tof_5_features].describe().T\n# -1 mean no sensor response","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:30:56.211283Z","iopub.execute_input":"2025-05-30T08:30:56.211565Z","iopub.status.idle":"2025-05-30T08:30:58.666185Z","shell.execute_reply.started":"2025-05-30T08:30:56.211542Z","shell.execute_reply":"2025-05-30T08:30:58.665571Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# check if any columns only have exactly 1 value:\nNUNIQUE1 = [c for c in train.columns if train[c].nunique()==1]\nNUNIQUE1","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:30:58.669224Z","iopub.execute_input":"2025-05-30T08:30:58.669438Z","iopub.status.idle":"2025-05-30T08:31:01.489251Z","shell.execute_reply.started":"2025-05-30T08:30:58.669422Z","shell.execute_reply":"2025-05-30T08:31:01.488488Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Naive Model","metadata":{}},{"cell_type":"code","source":"from sklearn.preprocessing import LabelEncoder\nfrom sklearn.ensemble import RandomForestClassifier\nfrom sklearn.model_selection import StratifiedShuffleSplit\nfrom sklearn.metrics import f1_score","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:31:01.490034Z","iopub.execute_input":"2025-05-30T08:31:01.490266Z","iopub.status.idle":"2025-05-30T08:31:02.021248Z","shell.execute_reply.started":"2025-05-30T08:31:01.490248Z","shell.execute_reply":"2025-05-30T08:31:02.020407Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"le = LabelEncoder()\ntrain['encoded_gesture'] = le.fit_transform(train['gesture'])\nunique_sequences = train[['sequence_id', 'encoded_gesture']].drop_duplicates()\nunique_sequence_ids = unique_sequences['sequence_id']\nunique_sequence_targets = unique_sequences['encoded_gesture']","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:31:02.022119Z","iopub.execute_input":"2025-05-30T08:31:02.022399Z","iopub.status.idle":"2025-05-30T08:31:02.189933Z","shell.execute_reply.started":"2025-05-30T08:31:02.022373Z","shell.execute_reply":"2025-05-30T08:31:02.189267Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train = train.dropna()\n\nsplitter = 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 = train[train['sequence_id'].isin(train_seq_ids)]\nX_val = train[train['sequence_id'].isin(val_seq_ids)]\n\ny_train = X_train['encoded_gesture']\ny_val = X_val['encoded_gesture']\n\n\ncol_to_drop = ['row_id','sequence_id','subject', 'orientation', 'behavior', 'phase', 'sequence_type']\n\nX_train = X_train[all_features].drop(columns=col_to_drop)\nX_val = X_val[all_features].drop(columns=col_to_drop)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:32:24.456954Z","iopub.execute_input":"2025-05-30T08:32:24.457251Z","iopub.status.idle":"2025-05-30T08:32:28.921465Z","shell.execute_reply.started":"2025-05-30T08:32:24.457230Z","shell.execute_reply":"2025-05-30T08:32:28.920606Z"}},"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\nall_original_gestures_in_train = train['gesture'].unique()\nall_original_gestures_in_train","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:32:31.176529Z","iopub.execute_input":"2025-05-30T08:32:31.177209Z","iopub.status.idle":"2025-05-30T08:32:31.217396Z","shell.execute_reply.started":"2025-05-30T08:32:31.177185Z","shell.execute_reply":"2025-05-30T08:32:31.216506Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# use default params\nrf_model = RandomForestClassifier(random_state=42, n_jobs=-1)\nrf_model.fit(X_train, y_train)\n\ny_val_pred = rf_model.predict(X_val)\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:32:32.476846Z","iopub.execute_input":"2025-05-30T08:32:32.477228Z","iopub.status.idle":"2025-05-30T08:34:00.887569Z","shell.execute_reply.started":"2025-05-30T08:32:32.477190Z","shell.execute_reply":"2025-05-30T08:34:00.886581Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"all_original_gestures_in_train = train['gesture'].unique()\nvalidation_score = competition_metric(y_val, y_val_pred, le, all_original_gestures_in_train)\nprint(f\"Validation Score: {validation_score:.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:34:32.692489Z","iopub.execute_input":"2025-05-30T08:34:32.692795Z","iopub.status.idle":"2025-05-30T08:34:32.789318Z","shell.execute_reply.started":"2025-05-30T08:34:32.692773Z","shell.execute_reply":"2025-05-30T08:34:32.788503Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"all_feature_cols = X_train.columns.to_list()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:34:56.669357Z","iopub.execute_input":"2025-05-30T08:34:56.669713Z","iopub.status.idle":"2025-05-30T08:34:56.673979Z","shell.execute_reply.started":"2025-05-30T08:34:56.669685Z","shell.execute_reply":"2025-05-30T08:34:56.673109Z"}},"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_feature_cols] = sequence_pd[all_feature_cols].fillna(-1)\n    X_inference = sequence_pd[all_feature_cols]\n    predicted_label_id = rf_model.predict(X_inference)[0]\n    predicted_gesture_str = le.inverse_transform([predicted_label_id])[0]\n    return predicted_gesture_str","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:35:02.536418Z","iopub.execute_input":"2025-05-30T08:35:02.536969Z","iopub.status.idle":"2025-05-30T08:35:02.541312Z","shell.execute_reply.started":"2025-05-30T08:35:02.536942Z","shell.execute_reply":"2025-05-30T08:35:02.540436Z"}},"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    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:35:05.354127Z","iopub.execute_input":"2025-05-30T08:35:05.354786Z","iopub.status.idle":"2025-05-30T08:35:07.099434Z","shell.execute_reply.started":"2025-05-30T08:35:05.354758Z","shell.execute_reply":"2025-05-30T08:35:07.098592Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# view submission file\npd.read_parquet('/kaggle/working/submission.parquet')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T08:35:07.561238Z","iopub.execute_input":"2025-05-30T08:35:07.561858Z","iopub.status.idle":"2025-05-30T08:35:07.682817Z","shell.execute_reply.started":"2025-05-30T08:35:07.561833Z","shell.execute_reply":"2025-05-30T08:35:07.681986Z"}},"outputs":[],"execution_count":null}]}