{"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":245758375,"sourceType":"kernelVersion"}],"dockerImageVersionId":31040,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"Train code is here: https://www.kaggle.com/code/jiazhuang/cmi-imu-only-lightgbm-train","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19"}},{"cell_type":"code","source":"import os\nimport polars as pl\nimport pandas as pd\nimport numpy as np","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T14:25:41.123010Z","iopub.execute_input":"2025-06-16T14:25:41.123267Z","iopub.status.idle":"2025-06-16T14:25:42.193922Z","shell.execute_reply.started":"2025-06-16T14:25:41.123247Z","shell.execute_reply":"2025-06-16T14:25:42.193102Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Load Model","metadata":{}},{"cell_type":"code","source":"import lightgbm as lgb\nfrom pathlib import Path\nimport joblib","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T14:25:42.194908Z","iopub.execute_input":"2025-06-16T14:25:42.195332Z","iopub.status.idle":"2025-06-16T14:25:49.436360Z","shell.execute_reply.started":"2025-06-16T14:25:42.195304Z","shell.execute_reply":"2025-06-16T14:25:49.435525Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"MODEL_DIR = '/kaggle/input/cmi-imu-only-lightgbm-train'\nmodels = []\nfor model_file in Path(MODEL_DIR).glob('lgb_model_fold*.txt'):\n    models.append(\n        lgb.Booster(model_file=model_file)\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T14:25:49.438056Z","iopub.execute_input":"2025-06-16T14:25:49.438665Z","iopub.status.idle":"2025-06-16T14:25:52.600056Z","shell.execute_reply.started":"2025-06-16T14:25:49.438644Z","shell.execute_reply":"2025-06-16T14:25:52.599374Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"label_encoder = joblib.load(f'{MODEL_DIR}/label_encoder.joblib')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T14:25:52.600785Z","iopub.execute_input":"2025-06-16T14:25:52.601007Z","iopub.status.idle":"2025-06-16T14:25:52.606325Z","shell.execute_reply.started":"2025-06-16T14:25:52.600987Z","shell.execute_reply":"2025-06-16T14:25:52.605707Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## FE","metadata":{}},{"cell_type":"code","source":"def q25(x):\n    return x.quantile(0.25)\n\ndef q75(x):\n    return x.quantile(0.75)\n\ndef kurt(x):\n    return x.kurt()\n\nagg_funs = ['mean', 'std', 'min', 'max', q25, q75, 'skew', kurt]\nseq_cols = ['acc_x', 'acc_y', 'acc_z', 'rot_w', 'rot_x', 'rot_y', 'rot_z']","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T14:25:52.607099Z","iopub.execute_input":"2025-06-16T14:25:52.607876Z","iopub.status.idle":"2025-06-16T14:25:52.623270Z","shell.execute_reply.started":"2025-06-16T14:25:52.607837Z","shell.execute_reply":"2025-06-16T14:25:52.622555Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"feat_cols = pd.read_csv(f'{MODEL_DIR}/feat_cols.txt', names=['feat']).feat.tolist()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T14:26:07.319575Z","iopub.execute_input":"2025-06-16T14:26:07.319875Z","iopub.status.idle":"2025-06-16T14:26:07.340514Z","shell.execute_reply.started":"2025-06-16T14:26:07.319849Z","shell.execute_reply":"2025-06-16T14:26:07.339874Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## API","metadata":{}},{"cell_type":"code","source":"def predict(sequence: pl.DataFrame, demographics: pl.DataFrame) -> str:\n    sequence = sequence.to_pandas()\n    demographics = demographics.to_pandas()\n\n    # FE\n    sequence = sequence.groupby(['sequence_id', 'subject']).agg({c: agg_funs for c in seq_cols})\n    sequence.columns = [x[0] + '_' + x[1] for x in sequence.columns]\n    sequence.reset_index(inplace=True)\n    \n    sequence = pd.merge(\n        sequence,\n        demographics,\n        on='subject',\n        how='left'\n    )\n    \n    feat_df = sequence[feat_cols]\n\n    # predict\n    preds = []\n    for model in models:\n        preds.append( model.predict(feat_df).argmax(axis=-1)[0] )\n    \n    voted_pred = pd.Series(preds).mode().iloc[0]\n    \n    return label_encoder.classes_[voted_pred]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T14:26:13.940386Z","iopub.execute_input":"2025-06-16T14:26:13.941029Z","iopub.status.idle":"2025-06-16T14:26:13.947124Z","shell.execute_reply.started":"2025-06-16T14:26:13.941002Z","shell.execute_reply":"2025-06-16T14:26:13.946442Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import kaggle_evaluation.cmi_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-16T14:26:15.533029Z","iopub.execute_input":"2025-06-16T14:26:15.533617Z","iopub.status.idle":"2025-06-16T14:26:17.525562Z","shell.execute_reply.started":"2025-06-16T14:26:15.533592Z","shell.execute_reply":"2025-06-16T14:26:17.524720Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}