{"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"},{"sourceId":12903930,"sourceType":"datasetVersion","datasetId":8164669},{"sourceId":552087,"sourceType":"modelInstanceVersion","modelInstanceId":421168,"modelId":438784},{"sourceId":553789,"sourceType":"modelInstanceVersion","modelInstanceId":422077,"modelId":439665},{"sourceId":554430,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":422304,"modelId":439880},{"sourceId":554432,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":422306,"modelId":439882},{"sourceId":555001,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":422623,"modelId":440188}],"dockerImageVersionId":31040,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\n\nimport pandas as pd\nimport polars as pl\n\nimport kaggle_evaluation.cmi_inference_server","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-09-01T15:33:27.516293Z","iopub.execute_input":"2025-09-01T15:33:27.516645Z","iopub.status.idle":"2025-09-01T15:33:30.740175Z","shell.execute_reply.started":"2025-09-01T15:33:27.516623Z","shell.execute_reply":"2025-09-01T15:33:30.739220Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nfrom tensorflow.keras.models import load_model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-01T15:33:30.741755Z","iopub.execute_input":"2025-09-01T15:33:30.742126Z","iopub.status.idle":"2025-09-01T15:33:47.865474Z","shell.execute_reply.started":"2025-09-01T15:33:30.742105Z","shell.execute_reply":"2025-09-01T15:33:47.864195Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"imuex_model_best = load_model(\"/kaggle/input/cmi_imu_extended_9/tensorflow2/default/1/imuex_model_9_1.h5\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-01T15:34:52.251779Z","iopub.execute_input":"2025-09-01T15:34:52.252098Z","iopub.status.idle":"2025-09-01T15:34:52.671574Z","shell.execute_reply.started":"2025-09-01T15:34:52.252074Z","shell.execute_reply":"2025-09-01T15:34:52.670862Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"target_classes = [\n    'Above ear - pull hair',\n    'Forehead - pull hairline',\n    'Forehead - scratch',\n    'Eyebrow - pull hair',\n    'Eyelash - pull hair',\n    'Neck - pinch skin',\n    'Neck - scratch',\n    'Cheek - pinch skin'\n]\nclass_map = {cls: i for i, cls in enumerate(target_classes)}\nclass_map","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-01T15:35:10.591426Z","iopub.execute_input":"2025-09-01T15:35:10.591777Z","iopub.status.idle":"2025-09-01T15:35:10.600215Z","shell.execute_reply.started":"2025-09-01T15:35:10.591755Z","shell.execute_reply":"2025-09-01T15:35:10.599049Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"imu_features =  [\n 'acc_x',\n 'acc_y',\n 'acc_z',\n 'rot_w',\n 'rot_x',\n 'rot_y',\n 'rot_z',\n 'acc_magnitude',\n 'jerk_x',\n 'jerk_y',\n 'jerk_z',\n 'jerk_magnitude']","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-01T15:35:38.781095Z","iopub.execute_input":"2025-09-01T15:35:38.781440Z","iopub.status.idle":"2025-09-01T15:35:38.786164Z","shell.execute_reply.started":"2025-09-01T15:35:38.781405Z","shell.execute_reply":"2025-09-01T15:35:38.785179Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def prepare_submission_sequences(df,columns,max_steps=400):\n\n    nan_columns_X = df.columns[df.isnull().any()].tolist()\n    print(\"Columns in X with NaNs Before:\\n\", nan_columns_X)\n    df = df.infer_objects(copy=False)\n    df[df.select_dtypes(include=[\"number\"]).columns] = df.select_dtypes(include=[\"number\"]).interpolate(method=\"linear\", axis=0)\n    nan_columns_X = df.columns[df.isnull().any()].tolist()\n    print(\"Columns in X with NaNs After:\\n\", nan_columns_X)\n    \n    df = df.sort_values(by=[\"sequence_id\", \"sequence_counter\"], \n                    ascending=[True, True]).reset_index(drop=True)\n\n  \n    df[\"acc_magnitude\"] = np.sqrt(df[\"acc_x\"]**2 + df[\"acc_y\"]**2 + df[\"acc_z\"]**2)\n\n    df[\"jerk_x\"] = df[\"acc_x\"].diff()   # difference between consecutive values\n    df[\"jerk_y\"] = df[\"acc_y\"].diff()\n    df[\"jerk_z\"] = df[\"acc_z\"].diff()\n\n    # magnitude of jerk\n    df[\"jerk_magnitude\"] = np.sqrt(df[\"jerk_x\"]**2 + df[\"jerk_y\"]**2 + df[\"jerk_z\"]**2)\n\n    # fill NaN from diff() with 0\n    df.fillna(0, inplace=True)\n\n    # Drop unnecessary columns early\n    df = df.drop(columns=[\"sequence_counter\"]) \n    \n    n_features = len(columns)\n\n    \n    # Find number of unique sequences\n    sequence_ids = df[\"sequence_id\"].unique()\n    n_sequences = len(sequence_ids)\n\n    # Preallocate final arrays\n    X = np.zeros((n_sequences, max_steps, n_features), dtype=np.float32)\n    Y = np.zeros((n_sequences,), dtype=np.float32)  \n    for i, seq_id in enumerate(sequence_ids):\n        if i % 100 ==0:\n            print(f\"Processing {i}/{n_sequences}\")\n\n        #imu\n        seq = df[df[\"sequence_id\"] == seq_id][columns].values.astype(np.float32)\n        seq_len = len(seq)\n        if seq_len > max_steps:\n            seq = seq[-max_steps:]\n        X[i, :seq_len, :] = seq\n    \n    return X","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-01T15:36:17.721204Z","iopub.execute_input":"2025-09-01T15:36:17.721602Z","iopub.status.idle":"2025-09-01T15:36:17.732336Z","shell.execute_reply.started":"2025-09-01T15:36:17.721576Z","shell.execute_reply":"2025-09-01T15:36:17.731258Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def predict(sequence: pl.DataFrame, demographics: pl.DataFrame) -> str:\n    df_test = sequence.to_pandas()\n    print(\"received df with shape\",df_test.shape)\n    \n    x_test = prepare_submission_sequences(df_test,imu_features)\n\n    print(\"prepared test\",x_test.shape)\n    prob = imuex_model_best.predict(x_test)\n    classpred = np.argmax(prob,axis=1)\n    if (classpred[0]==8):\n        return 'Text on phone'\n    print(\"Predicted labels:\", target_classes[classpred[0]])\n    return target_classes[classpred[0]]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-01T15:42:33.521261Z","iopub.execute_input":"2025-09-01T15:42:33.521597Z","iopub.status.idle":"2025-09-01T15:42:33.527997Z","shell.execute_reply.started":"2025-09-01T15:42:33.521573Z","shell.execute_reply":"2025-09-01T15:42:33.526912Z"}},"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-09-01T15:42:39.276157Z","iopub.execute_input":"2025-09-01T15:42:39.276631Z","iopub.status.idle":"2025-09-01T15:42:43.103162Z","shell.execute_reply.started":"2025-09-01T15:42:39.276596Z","shell.execute_reply":"2025-09-01T15:42:43.102028Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}