{"metadata":{"kernelspec":{"display_name":"Python 3 (ipykernel)","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.12.7"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":102335,"databundleVersionId":12518947,"sourceType":"competition"},{"sourceId":487858,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":376126,"modelId":396846}],"dockerImageVersionId":31089,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nimport pandas as pd\nimport numpy as np\nimport scipy\nimport xgboost as xgb\nimport random\nimport os\nimport joblib\n\n\nfrom sklearn.metrics import f1_score, accuracy_score\nfrom sklearn.metrics import accuracy_score, confusion_matrix, classification_report\nfrom xgboost import XGBClassifier\nfrom sklearn.model_selection import train_test_split, GridSearchCV\nfrom sklearn.preprocessing import LabelEncoder\nfrom sklearn.preprocessing import OneHotEncoder\nfrom sklearn.compose import ColumnTransformer\nfrom sklearn.preprocessing import OrdinalEncoder\nfrom pathlib import Path\nfrom scipy.spatial.transform import Rotation\nfrom sklearn.feature_selection import SelectFromModel","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T23:33:03.893318Z","iopub.execute_input":"2025-07-24T23:33:03.893969Z","iopub.status.idle":"2025-07-24T23:33:03.899998Z","shell.execute_reply.started":"2025-07-24T23:33:03.893933Z","shell.execute_reply":"2025-07-24T23:33:03.899269Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"KAGGLE = True\nTRAIN = False \nGRIDSEARCH = False\nSHORTENSEQUENCE = False\nVERSION = 31\nMODELFILENAME = 'motion_only_simple_xgboost-v' + str(VERSION) + '.json'\nCLASSFILENAME = 'gesture_classes-v' + str(VERSION) + '.npy'\nPECENTLISTFILENAME = 'percent_list-v' + str(VERSION) + '.npy'\nLENGTHLISTFILENAME = 'length_list-v' + str(VERSION) + '.npy'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T23:33:03.901292Z","iopub.execute_input":"2025-07-24T23:33:03.901582Z","iopub.status.idle":"2025-07-24T23:33:03.919030Z","shell.execute_reply.started":"2025-07-24T23:33:03.901561Z","shell.execute_reply":"2025-07-24T23:33:03.918036Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"random_seed = 42\ndef seed_everything(seed):\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    random.seed(seed)\n    np.random.seed(seed)\nseed_everything(seed=random_seed)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T23:33:03.919972Z","iopub.execute_input":"2025-07-24T23:33:03.920351Z","iopub.status.idle":"2025-07-24T23:33:03.934387Z","shell.execute_reply.started":"2025-07-24T23:33:03.920319Z","shell.execute_reply":"2025-07-24T23:33:03.933374Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load the datasets\nif KAGGLE:\n    import polars as pl\n    DATA_DIR = Path('/kaggle/input/cmi-detect-behavior-with-sensor-data')\n    EXPORT_DIR = Path('/kaggle/input/motion-only-xgboost/other/default/15')\n    test_df = pl.read_csv(DATA_DIR / \"test.csv\")\n    test_dem_df = pl.read_csv(DATA_DIR / \"test_demographics.csv\")\nelse:\n    DATA_DIR = Path('.')\n    EXPORT_DIR = Path('.')\n    test_df = pd.read_csv(DATA_DIR / \"test.csv\")\n    test_dem_df = pd.read_csv(DATA_DIR / \"test_demographics.csv\")\n\nif TRAIN:\n    train_df = pd.read_csv(DATA_DIR / \"train.csv\")\n    train_dem_df = pd.read_csv(DATA_DIR / \"train_demographics.csv\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T23:33:03.936261Z","iopub.execute_input":"2025-07-24T23:33:03.936579Z","iopub.status.idle":"2025-07-24T23:33:03.972623Z","shell.execute_reply.started":"2025-07-24T23:33:03.936547Z","shell.execute_reply":"2025-07-24T23:33:03.971732Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"numeric_columns_accel = [\"acc_x\", \"acc_y\", \"acc_z\"]\nnumeric_columns_accel_no_gravity = [\"acc_x_no_gravity\", \"acc_y_no_gravity\", \"acc_z_no_gravity\"]\nnumeric_columns_rotation = [\"rot_w\", \"rot_x\", \"rot_y\", \"rot_z\"]\nnumeric_columns_euler_rotation = [\"rot_euler_x\", \"rot_euler_y\", \"rot_euler_z\"]\nnumeric_columns_thermal = [f\"thm_{i}\" for i in range(1, 6)]\nnumeric_columns_tof = [f\"tof_{i}_v{j}\" for i in range(1, 6) for j in range(64)]\nnumeric_columns_tof_mean = [f\"tof_{i}_mean\" for i in range(1, 6)]\ntrain_categorical_columns = ['sequence_type', 'subject', 'gesture', 'orientation', 'behavior']\ntrain_demographics_categorical_columns = [\n    'subject',\n    'adult_child',\n    'sex',\n    'handedness'\n]\ntrain_demographics_numerical_columns = [\n    'age',\n    'height_cm',\n    'shoulder_to_wrist_cm',\n    'elbow_to_wrist_cm'\n]\n\ntrain_demographics_columns_to_use = ['subject', 'handedness']","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T23:33:03.973745Z","iopub.execute_input":"2025-07-24T23:33:03.973982Z","iopub.status.idle":"2025-07-24T23:33:03.981013Z","shell.execute_reply.started":"2025-07-24T23:33:03.973963Z","shell.execute_reply":"2025-07-24T23:33:03.980133Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"target_gestures = [\n            'Above ear - pull hair',\n            'Cheek - pinch skin',\n            'Eyebrow - pull hair',\n            'Eyelash - pull hair',\n            'Forehead - pull hairline',\n            'Forehead - scratch',\n            'Neck - pinch skin',\n            'Neck - scratch',\n        ]\nnon_target_gestures = [\n            'Write name on leg',\n            'Wave hello',\n            'Glasses on/off',\n            'Text on phone',\n            'Write name in air',\n            'Feel around in tray and pull out an object',\n            'Scratch knee/leg skin',\n            'Pull air toward your face',\n            'Drink from bottle/cup',\n            'Pinch knee/leg skin'\n        ]\n\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T23:33:03.982100Z","iopub.execute_input":"2025-07-24T23:33:03.982448Z","iopub.status.idle":"2025-07-24T23:33:04.000781Z","shell.execute_reply.started":"2025-07-24T23:33:03.982417Z","shell.execute_reply":"2025-07-24T23:33:03.999615Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Create the features","metadata":{}},{"cell_type":"code","source":"def remove_gravity_from_acc(df):\n\n    acc_values = df[['acc_x', 'acc_y', 'acc_z']].values\n    quat_values = df[['rot_x', 'rot_y', 'rot_z', 'rot_w']].values\n\n    num_samples = acc_values.shape[0]\n    linear_accel = np.zeros_like(acc_values)\n\n    gravity = np.array([0, 0, 9.81])\n\n    for i in range(num_samples):\n        if np.all(np.isnan(quat_values[i])) or np.all(np.isclose(quat_values[i], 0)):\n            linear_accel[i, :] = acc_values[i, :] \n            continue\n\n        try:\n            rotation = Rotation.from_quat(quat_values[i])\n            gravity_sensor_frame = rotation.apply(gravity, inverse=True)\n            linear_accel[i, :] = acc_values[i, :] - gravity_sensor_frame\n        except ValueError:\n             linear_accel[i, :] = acc_values[i, :]\n\n    df['acc_x_no_gravity'] = linear_accel[:,0]\n    df['acc_y_no_gravity'] = linear_accel[:,1]\n    df['acc_z_no_gravity'] = linear_accel[:,2]\n\n    \"\"\"\n    try:\n        euler_angles = rotation.as_euler('xyz', degrees=True)\n        df['rot_euler_x'] = euler_angles[0]\n        df['rot_euler_y'] = euler_angles[1]\n        df['rot_euler_z'] = euler_angles[2]\n    except ValueError:\n        df['rot_euler_x'] = np.nan\n        df['rot_euler_y'] = np.nan\n        df['rot_euler_z'] = np.nan\n    \"\"\"\n    return df\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T23:33:04.001896Z","iopub.execute_input":"2025-07-24T23:33:04.002180Z","iopub.status.idle":"2025-07-24T23:33:04.018220Z","shell.execute_reply.started":"2025-07-24T23:33:04.002159Z","shell.execute_reply":"2025-07-24T23:33:04.017122Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def prepare_tof_data(df):\n    #df[numeric_columns_tof] = df[numeric_columns_tof].ffill().bfill().fillna(-1)\n    # 255 corresponds to the largest distance from the ToF sensor\n    for col in numeric_columns_tof:\n        df.loc[df[col] == -1, col] = 256\n        \n    added_cols = {}\n    for i in range(1, 6):\n        cols = [f\"tof_{i}_v{j}\"  for j in range(64)]\n        added_cols[f\"tof_{i}_mean\"] = df[cols].mean(axis=1)\n        added_cols[f\"tof_{i}_max\"] = df[cols].max(axis=1)\n        added_cols[f\"tof_{i}_min\"] = df[cols].min(axis=1)\n        added_cols[f\"tof_{i}_median\"] = df[cols].median(axis=1)\n        added_cols[f\"tof_{i}_std\"] = df[cols].std(axis=1)\n        #added_cols[f\"tof_{i}_skew\"] = df[cols].skew(axis=1)\n        #added_cols[f\"tof_{i}_iqr\"] = df[cols].quantile(0.75) - df[cols].quantile(0.25)\n    new_cols = pd.DataFrame(added_cols)\n    return pd.concat([df, new_cols], axis=1) ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T23:33:04.019701Z","iopub.execute_input":"2025-07-24T23:33:04.020010Z","iopub.status.idle":"2025-07-24T23:33:04.038102Z","shell.execute_reply.started":"2025-07-24T23:33:04.019977Z","shell.execute_reply":"2025-07-24T23:33:04.036951Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def create_features_seq(df, train_bool):\n    if train_bool:\n        gesture = df['gesture'].iloc[0]\n    subject = df['subject'].iloc[0]\n    sequence_id = df['sequence_id'].iloc[0]\n    handedness = df['handedness'].iloc[0]\n\n    #  components\n    seq_df = df[numeric_columns_accel + numeric_columns_rotation + numeric_columns_accel_no_gravity + \n                numeric_columns_thermal]\n    \n    math_df = seq_df.apply([np.mean, np.max, np.min, np.median, np.std])\n    iqr = seq_df.quantile(0.75) - seq_df.quantile(0.25)\n    skew = seq_df.skew()\n    kurtosis = seq_df.kurtosis()\n    energy = seq_df.apply(lambda num: num**2).sum()/len(seq_df)\n\n    abs_signal = seq_df.apply(lambda num: abs(num)).sum()/len(seq_df)\n    sma_accel = abs_signal[numeric_columns_accel].sum()\n    sma_accel_no_gravity = abs_signal[numeric_columns_accel_no_gravity].sum()\n    sma_rotation = abs_signal[numeric_columns_rotation].sum()\n    #sma_euler_rotation = abs_signal[numeric_columns_euler_rotation].sum()\n    \n    concat_df = pd.concat([iqr, skew, kurtosis, energy], axis=1)\n    concat_df.columns = ['iqr', 'skew', 'kurtosis', 'energy']\n    concat_df = concat_df.transpose()\n    concat_df = pd.concat([math_df, concat_df], axis=0)\n\n    concat_df['func'] = concat_df.index\n    concat_df = concat_df.melt(id_vars=['func'])\n    concat_df['var_name'] = concat_df['variable'] + '_' + concat_df['func']\n    concat_df = concat_df.drop(columns=['func', 'variable'])\n    \n    new_row = pd.DataFrame({'var_name': ['sma_accel',\n                                         'sma_accel_no_gravity',\n                                         'sma_rotation',\n                                         'subject',\n                                         'sequence_id', \n                                        'handedness'], \n                            'value': [sma_accel,\n                                      sma_accel_no_gravity,\n                                      sma_rotation,\n                                      subject,\n                                      sequence_id,\n                                     handedness]})\n    \n\n    # 255 corresponds to the largest distance from the ToF sensor\n    \"\"\"\n    for col in numeric_columns_tof:\n        seq_df[seq_df[col] == -1] = 256\n    \"\"\"\n    \n    \n    # time of flight\n    tof_cols = {}\n    for i in range(1, 6):\n        cols = [f\"tof_{i}_v{j}\"  for j in range(64)]\n        tof_values = df[cols].to_numpy().flatten()\n        tof_values[tof_values == -1] = 256\n        if sum(np.isnan(tof_values)) <= 0.8 * len(tof_values):\n            tof_cols[f\"tof_{i}_mean\"] = np.nanmean(tof_values)\n            tof_cols[f\"tof_{i}_max\"] = np.nanmax(tof_values)\n            tof_cols[f\"tof_{i}_min\"] = np.nanmin(tof_values)\n            tof_cols[f\"tof_{i}_median\"] = np.nanmedian(tof_values)\n            tof_cols[f\"tof_{i}_std\"] = np.nanstd(tof_values)\n        else:\n            tof_cols[f\"tof_{i}_mean\"] = np.nan\n            tof_cols[f\"tof_{i}_max\"] = np.nan\n            tof_cols[f\"tof_{i}_min\"] = np.nan\n            tof_cols[f\"tof_{i}_median\"] = np.nan\n            tof_cols[f\"tof_{i}_std\"] = np.nan\n        #tof_cols[f\"tof_{i}_skew\"] = np.skew(df[cols].to_numpy())\n        #tof_cols[f\"tof_{i}_iqr\"] = seq_df[cols].quantile(0.75) - seq_df[cols].quantile(0.25)\n    \n    tof_df = pd.DataFrame(tof_cols, index =['value']).transpose()\n    tof_df.index.names = ['var_name']\n    tof_df = tof_df.reset_index()\n\n    #concat_df = pd.concat([concat_df, new_row, tof_cols], ignore_index=True)\n\n    concat_df = pd.concat([concat_df, new_row, tof_df], ignore_index=True)\n    \n    if train_bool:\n        new_row = pd.DataFrame({'var_name': ['gesture'],'value': [gesture]})\n        concat_df = pd.concat([concat_df, new_row], ignore_index=True)\n    \n    concat_df = concat_df.set_index('var_name')\n\n    return concat_df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T23:33:04.040730Z","iopub.execute_input":"2025-07-24T23:33:04.040998Z","iopub.status.idle":"2025-07-24T23:33:04.063762Z","shell.execute_reply.started":"2025-07-24T23:33:04.040977Z","shell.execute_reply":"2025-07-24T23:33:04.062947Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def create_feature_df(df):\n    cat_list = []\n    for ind, sequence_id in enumerate(df['sequence_id'].unique()):\n        if ind % 100 == 0:\n            print(ind)\n        seq = df[df['sequence_id'] == sequence_id]\n        if SHORTENSEQUENCE:\n            gesture_percent = predict_gesture_percent(len(seq))\n            gesture_ind = round(len(seq) * gesture_percent)\n            seq = seq.iloc[-gesture_ind:-1]\n        cat_list.append(create_features_seq(seq, TRAIN))    \n    ret_df = pd.concat(cat_list, axis=1)\n    ret_df = ret_df.transpose().reset_index().drop(columns='index')\n    return ret_df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T23:33:04.064755Z","iopub.execute_input":"2025-07-24T23:33:04.065098Z","iopub.status.idle":"2025-07-24T23:33:04.084055Z","shell.execute_reply.started":"2025-07-24T23:33:04.065075Z","shell.execute_reply":"2025-07-24T23:33:04.083186Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def split_data(df):\n    X, y = df.drop(['gesture', 'subject', 'sequence_id'], axis=1), df[['gesture']]\n    X = X.apply(pd.to_numeric)\n    \n    # Encode y to numeric\n    le = LabelEncoder()\n    y_encoded = le.fit_transform(np.ravel(y))\n    gesture_classes = le.classes_\n    np.save(EXPORT_DIR / CLASSFILENAME, le.classes_)\n    \n    # Split the data\n    X_train, X_test, y_train, y_test = train_test_split(X, y_encoded, \n                                                        random_state=1, \n                                                        stratify=y_encoded)\n    return X_train, X_test, y_train, y_test","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T23:33:04.085020Z","iopub.execute_input":"2025-07-24T23:33:04.085378Z","iopub.status.idle":"2025-07-24T23:33:04.106439Z","shell.execute_reply.started":"2025-07-24T23:33:04.085349Z","shell.execute_reply":"2025-07-24T23:33:04.105552Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def train_model(X_train, X_test, y_train, y_test):\n    \n    params = {\n        'objective': 'multi:softmax',\n        'eval_metric': 'merror',\n        'early_stopping_rounds': 10,\n        'random_state': random_seed,\n        'max_depth': 6, #depth of tree\n        'min_child_weight': 5, # minimum number of instances needed to be in each node \n        'subsample': 1.0, #fraction of observations used for each tree\n        'colsample_bytree': 0.8, #percentage of features ( columns ) will be used for building each tree\n        'learning_rate': 0.3   \n    }\n\n    \n    \"\"\"\n    params = {\n        'objective': 'multi:softmax',\n        'eval_metric': 'merror',\n        'early_stopping_rounds': 10,\n        'random_state': random_seed,  \n    }\n    \"\"\"\n    \n    class_weights = dict(enumerate(len(y_train) / (len(np.unique(y_train)) * np.bincount(y_train))))\n    sample_weight = np.array([class_weights[label] for label in y_train])\n    \n    # Instantiate XGBClassifier with the parameters\n    model = xgb.XGBClassifier(**params)\n    # Train the model with early stopping\n    model.fit(X_train, y_train, eval_set=[(X_test, y_test)], sample_weight=sample_weight)\n\n    # Analyze Model\n    # Retrieve the merror values from the training process\n    results = model.evals_result()\n    epochs = len(results['validation_0']['merror'])\n    x_axis = range(0, epochs)\n    \n    # Plot the merror values\n    plt.figure()\n    plt.plot(x_axis, results['validation_0']['merror'], label='Test')\n    plt.legend()\n    plt.xlabel('Number of Boosting Rounds')\n    plt.ylabel('Multiclass Classification Error')\n    plt.title('XGBoost merror Performance')\n    plt.show()\n    \n    y_pred = model.predict(X_test)\n\n    # Evaluate model performance\n    accuracy = accuracy_score(y_test, y_pred)\n    f1_score_val = f1_score(y_pred,y_test,average='macro')\n    confusion = confusion_matrix(y_test, y_pred)\n    \n    print(f\"Accuracy: {accuracy:.3f}\")\n    print(f\"F1 Score: {f1_score_val:.3f}\")\n    \n    print(f\"Confusion Matrix:\\n{confusion}\")\n    \n    print(\"\\n Classification Report:\\n\",\n          classification_report(y_test, y_pred))\n\n    fig, ax = plt.subplots(figsize=(4, 30))\n    xgb.plot_importance(model, ax=ax)\n    plt.show()\n    \n    return model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T23:33:04.107552Z","iopub.execute_input":"2025-07-24T23:33:04.107857Z","iopub.status.idle":"2025-07-24T23:33:04.124132Z","shell.execute_reply.started":"2025-07-24T23:33:04.107828Z","shell.execute_reply":"2025-07-24T23:33:04.123461Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def param_search(df):\n    param_grid = {\n        'max_depth': [4, 6, 8], #depth of tree, default=6\n        'min_child_weight': [1, 3, 5], #default=1\n        'subsample': [0.6, 0.8, 1.0], #fraction of observations used for each tree. default=1 \n        'colsample_bytree': [0.6, 0.8, 1], #percentage of features ( columns ) will be used for building each tree, default=1\n        'learning_rate': [0.03, 0.1, 0.3] #default = 0.3\n    }\n    \n    params = {\n        'objective': 'multi:softmax',\n        'eval_metric': 'merror',\n        'random_state': random_seed\n    }\n\n    X_train, X_test, y_train, y_test = split_data(df)\n\n    \n    \n    # Create XGBoost classifier\n    model = xgb.XGBClassifier(**params)\n    \n    # Perform grid search\n    grid_search = GridSearchCV(estimator=model, param_grid=param_grid, cv=4, n_jobs=-1, verbose=3, scoring='f1_macro')\n    grid_search.fit(X_train, y_train)\n    \n    # Print best parameters\n    print(f\"Best parameters: {grid_search.best_params_}\")\n    print(f\"Best score: {grid_search.best_score_}\")\n\n#","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T23:33:04.125090Z","iopub.execute_input":"2025-07-24T23:33:04.125416Z","iopub.status.idle":"2025-07-24T23:33:04.143570Z","shell.execute_reply.started":"2025-07-24T23:33:04.125394Z","shell.execute_reply":"2025-07-24T23:33:04.142564Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def construct_gesture_percent_lists(df, window_size):\n    gesture_percent_list = []\n    length_seq = []\n    concat_list = []\n    for ind, sequence_id in enumerate(df['sequence_id'].unique()):\n        if ind % 100 == 0:\n            print(ind)\n        seq = df[df['sequence_id'] == sequence_id]\n        length_seq.append(len(seq))\n        if 'Performs gesture' in seq.value_counts('behavior'):\n            gesture_percent =seq.value_counts('behavior')['Performs gesture'] /len(seq)\n        gesture_percent_list.append(gesture_percent)\n    test_df = pd.DataFrame({'length': pd.Series(length_seq),  'percent':pd.Series(gesture_percent_list)}).sort_values(by='length')\n    for ind in np.arange(window_size,len(test_df),window_size):\n        concat_list.append(test_df.iloc[ind-window_size:ind].mean())\n    ret_df = pd.concat(concat_list, axis=1)\n    length_list = np.array(ret_df.loc['length', :].values.flatten().tolist())\n    percent_list = np.array(ret_df.loc['percent', :].values.flatten().tolist())\n    length_list = length_list + 1e-3*np.random.rand(len(length_list))\n    \n    np.save(EXPORT_DIR / PECENTLISTFILENAME, percent_list)\n    np.save(EXPORT_DIR / LENGTHLISTFILENAME, length_list)\n    \n    return length_list, percent_list","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T23:33:04.144614Z","iopub.execute_input":"2025-07-24T23:33:04.144855Z","iopub.status.idle":"2025-07-24T23:33:04.159593Z","shell.execute_reply.started":"2025-07-24T23:33:04.144832Z","shell.execute_reply":"2025-07-24T23:33:04.158741Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def predict_gesture_percent(x):\n    \n    percent_list = np.load(EXPORT_DIR / PECENTLISTFILENAME, allow_pickle=True)\n    length_list = np.load(EXPORT_DIR / LENGTHLISTFILENAME, allow_pickle=True)\n    \n    if x < length_list[0]:\n        return percent_list[0]\n    elif x > length_list[-1]:\n        return percent_list[-1]\n    else:\n        itemindex = np.where(np.array(length_list) > x)[0][0]\n        return 0.5*(percent_list[itemindex]+percent_list[itemindex-1])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T23:33:04.160441Z","iopub.execute_input":"2025-07-24T23:33:04.160753Z","iopub.status.idle":"2025-07-24T23:33:04.179871Z","shell.execute_reply.started":"2025-07-24T23:33:04.160710Z","shell.execute_reply":"2025-07-24T23:33:04.179014Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def f1_eval(y_pred, y_true):\n    \"\"\"Custom F1 evaluation function for XGBoost\"\"\"\n    y_true = y_true.get_label()\n    y_pred = (y_pred > 0.5).astype(int)\n    f1 = f1_score(y_true, y_pred)\n    return 'f1', f1","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T23:33:04.180952Z","iopub.execute_input":"2025-07-24T23:33:04.181259Z","iopub.status.idle":"2025-07-24T23:33:04.195488Z","shell.execute_reply.started":"2025-07-24T23:33:04.181230Z","shell.execute_reply":"2025-07-24T23:33:04.194550Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def remove_thermal_outliers_constant(df):    \n    for col in numeric_columns_thermal:\n        df.loc[df[col] < 17.5, col] = np.nan\n        df.loc[df[col] > 40, col] = np.nan\n    return df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T23:33:04.196632Z","iopub.execute_input":"2025-07-24T23:33:04.196891Z","iopub.status.idle":"2025-07-24T23:33:04.210527Z","shell.execute_reply.started":"2025-07-24T23:33:04.196868Z","shell.execute_reply":"2025-07-24T23:33:04.209567Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if TRAIN:\n    train_df = train_df.merge(train_dem_df[train_demographics_columns_to_use], on='subject', how='left')\n    train_df = remove_gravity_from_acc(train_df)\n    #tof_data = prepare_tof_data(train_df)\n    train_df = remove_thermal_outliers_constant(train_df)\n    train_df[numeric_columns_tof].replace(-1, 256, inplace=True)\n    if SHORTENSEQUENCE:\n        length_list, percent_list = construct_gesture_percent_lists(train_df, 10)\n    feature_df = create_feature_df(train_df)\n    #feature_df = pd.concat([feature_df, tof_data], axis = 1)\n    X_train, X_test, y_train, y_test = split_data(feature_df)\n    model = train_model(X_train, X_test, y_train, y_test)\n    model.save_model(EXPORT_DIR / MODELFILENAME)\n    #joblib.dump(model,)\n  ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T23:33:04.211486Z","iopub.execute_input":"2025-07-24T23:33:04.211792Z","iopub.status.idle":"2025-07-24T23:33:04.228381Z","shell.execute_reply.started":"2025-07-24T23:33:04.211759Z","shell.execute_reply":"2025-07-24T23:33:04.227318Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if GRIDSEARCH:\n    param_search(feature_df)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T23:33:04.231480Z","iopub.execute_input":"2025-07-24T23:33:04.231790Z","iopub.status.idle":"2025-07-24T23:33:04.245182Z","shell.execute_reply.started":"2025-07-24T23:33:04.231769Z","shell.execute_reply":"2025-07-24T23:33:04.244303Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def predict_pandas(sequence: pd.DataFrame, demographics: pd.DataFrame) -> str:\n    gesture_classes = np.load(EXPORT_DIR / CLASSFILENAME, allow_pickle=True)\n    model_reload = xgb.XGBClassifier()\n    model_reload.load_model(EXPORT_DIR / MODELFILENAME)\n    sequence = sequence.merge(demographics[train_demographics_columns_to_use], on='subject', how='left')\n    sequence = remove_gravity_from_acc(sequence)\n    #tof_data = prepare_tof_data(sequence)\n    sequence = remove_thermal_outliers_constant(sequence)\n    feature_df = create_features_seq(sequence, False)\n    #feature_df = pd.concat([feature_df, tof_data], axis=1)\n    feature_df = feature_df.drop(['sequence_id', 'subject'])\n    feature_df = feature_df.apply(pd.to_numeric)\n    feature_df = feature_df.transpose().reset_index().drop(columns='index')\n    return gesture_classes[model_reload.predict(feature_df)[0]]\n\nif KAGGLE:\n    import polars as pl\n    \n    def predict(sequence: pl.DataFrame, demographics: pl.DataFrame) -> str:\n        sequence = sequence.to_pandas()\n        demographics = demographics.to_pandas()\n        return predict_pandas(sequence, demographics)\n    \n    print(predict(test_df,test_dem_df))\nelse:\n    print(predict_pandas(test_df,test_dem_df))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T23:33:04.246221Z","iopub.execute_input":"2025-07-24T23:33:04.246701Z","iopub.status.idle":"2025-07-24T23:33:04.473070Z","shell.execute_reply.started":"2025-07-24T23:33:04.246670Z","shell.execute_reply":"2025-07-24T23:33:04.472235Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if KAGGLE:\n    import kaggle_evaluation.cmi_inference_server    \n    inference_server = kaggle_evaluation.cmi_inference_server.CMIInferenceServer(predict)\n    \n    if os.getenv('KAGGLE_IS_COMPETITION_RERUN'):\n        inference_server.serve()\n    else:\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","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T23:33:04.473947Z","iopub.execute_input":"2025-07-24T23:33:04.474196Z","iopub.status.idle":"2025-07-24T23:33:05.971210Z","shell.execute_reply.started":"2025-07-24T23:33:04.474177Z","shell.execute_reply":"2025-07-24T23:33:05.970336Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}