{"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":245653776,"sourceType":"kernelVersion"}],"dockerImageVersionId":31040,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\n%matplotlib inline","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-06-16T13:53:03.194092Z","iopub.execute_input":"2025-06-16T13:53:03.194917Z","iopub.status.idle":"2025-06-16T13:53:03.552734Z","shell.execute_reply.started":"2025-06-16T13:53:03.194889Z","shell.execute_reply":"2025-06-16T13:53:03.551743Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Metric","metadata":{}},{"cell_type":"code","source":"import kagglehub\nmetric = kagglehub.package_import('jiazhuang/cmi-2025-metric')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T13:53:03.554218Z","iopub.execute_input":"2025-06-16T13:53:03.554622Z","iopub.status.idle":"2025-06-16T13:53:05.068481Z","shell.execute_reply.started":"2025-06-16T13:53:03.5546Z","shell.execute_reply":"2025-06-16T13:53:05.067646Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_competition_score(true, pred):\n    assert len(true) == len(pred)\n    N = len(true)\n    true = pd.DataFrame({'id': range(N), 'gesture': true})\n    pred = pd.DataFrame({'id': range(N), 'gesture': pred})\n    return metric.score(true, pred, 'id')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T13:53:05.069593Z","iopub.execute_input":"2025-06-16T13:53:05.070713Z","iopub.status.idle":"2025-06-16T13:53:05.077338Z","shell.execute_reply.started":"2025-06-16T13:53:05.070656Z","shell.execute_reply":"2025-06-16T13:53:05.075831Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Load Data","metadata":{}},{"cell_type":"code","source":"DATA_ROOT = '/kaggle/input/cmi-detect-behavior-with-sensor-data/'\n\ntrain_df = pd.read_csv(f'{DATA_ROOT}/train.csv')\ntrain_demo_df = pd.read_csv(f'{DATA_ROOT}/train_demographics.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T13:53:05.078387Z","iopub.execute_input":"2025-06-16T13:53:05.079145Z","iopub.status.idle":"2025-06-16T13:53:42.397206Z","shell.execute_reply.started":"2025-06-16T13:53:05.078845Z","shell.execute_reply":"2025-06-16T13:53:42.396477Z"}},"outputs":[],"execution_count":null},{"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-16T13:53:42.399146Z","iopub.execute_input":"2025-06-16T13:53:42.399408Z","iopub.status.idle":"2025-06-16T13:53:42.404785Z","shell.execute_reply.started":"2025-06-16T13:53:42.399388Z","shell.execute_reply":"2025-06-16T13:53:42.403776Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"agg_train_df = train_df.groupby(['sequence_id', 'subject']).agg({c: agg_funs for c in seq_cols})\n\nagg_train_df.columns = [x[0] + '_' + x[1] for x in agg_train_df.columns]\nagg_train_df.reset_index(inplace=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T13:53:42.405774Z","iopub.execute_input":"2025-06-16T13:53:42.406033Z","iopub.status.idle":"2025-06-16T13:54:36.090132Z","shell.execute_reply.started":"2025-06-16T13:53:42.406014Z","shell.execute_reply":"2025-06-16T13:54:36.089163Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"agg_train_df = pd.merge(\n    agg_train_df,\n    train_demo_df,\n    on='subject',\n    how='left'\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T13:54:36.091167Z","iopub.execute_input":"2025-06-16T13:54:36.091482Z","iopub.status.idle":"2025-06-16T13:54:36.109568Z","shell.execute_reply.started":"2025-06-16T13:54:36.091456Z","shell.execute_reply":"2025-06-16T13:54:36.108534Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"agg_train_df['label'] = agg_train_df.sequence_id.map(train_df.groupby('sequence_id').gesture.apply(lambda x: x.iloc[0]))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T13:54:36.110908Z","iopub.execute_input":"2025-06-16T13:54:36.111218Z","iopub.status.idle":"2025-06-16T13:54:36.327867Z","shell.execute_reply.started":"2025-06-16T13:54:36.111192Z","shell.execute_reply":"2025-06-16T13:54:36.326911Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"agg_train_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T13:54:36.328844Z","iopub.execute_input":"2025-06-16T13:54:36.329137Z","iopub.status.idle":"2025-06-16T13:54:36.360982Z","shell.execute_reply.started":"2025-06-16T13:54:36.32911Z","shell.execute_reply":"2025-06-16T13:54:36.360147Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"feat_cols = [c for c in agg_train_df.columns if c not in {'sequence_id', 'subject', 'label'}]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T13:54:36.361975Z","iopub.execute_input":"2025-06-16T13:54:36.362308Z","iopub.status.idle":"2025-06-16T13:54:36.366524Z","shell.execute_reply.started":"2025-06-16T13:54:36.362284Z","shell.execute_reply":"2025-06-16T13:54:36.365854Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pd.Series(feat_cols).to_csv('feat_cols.txt', index=False, header=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T13:54:36.367416Z","iopub.execute_input":"2025-06-16T13:54:36.367708Z","iopub.status.idle":"2025-06-16T13:54:36.390622Z","shell.execute_reply.started":"2025-06-16T13:54:36.367659Z","shell.execute_reply":"2025-06-16T13:54:36.389738Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"out = pd.read_csv('feat_cols.txt', names=['feat']).feat.tolist()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T13:54:36.391592Z","iopub.execute_input":"2025-06-16T13:54:36.391851Z","iopub.status.idle":"2025-06-16T13:54:36.407612Z","shell.execute_reply.started":"2025-06-16T13:54:36.391833Z","shell.execute_reply":"2025-06-16T13:54:36.406597Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"out == feat_cols","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T13:54:36.408698Z","iopub.execute_input":"2025-06-16T13:54:36.409038Z","iopub.status.idle":"2025-06-16T13:54:36.426112Z","shell.execute_reply.started":"2025-06-16T13:54:36.409Z","shell.execute_reply":"2025-06-16T13:54:36.425368Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Model","metadata":{}},{"cell_type":"code","source":"import lightgbm as lgb\nfrom sklearn.model_selection import KFold, StratifiedGroupKFold\nfrom sklearn.preprocessing import LabelEncoder\nimport joblib","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T13:54:36.428559Z","iopub.execute_input":"2025-06-16T13:54:36.428835Z","iopub.status.idle":"2025-06-16T13:54:41.706065Z","shell.execute_reply.started":"2025-06-16T13:54:36.428816Z","shell.execute_reply":"2025-06-16T13:54:41.705126Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"label_encoder = LabelEncoder()\nlabel_encoder.fit(agg_train_df.label)\nagg_train_df['label_code'] = label_encoder.transform(agg_train_df.label)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T13:54:46.913792Z","iopub.execute_input":"2025-06-16T13:54:46.914427Z","iopub.status.idle":"2025-06-16T13:54:46.922594Z","shell.execute_reply.started":"2025-06-16T13:54:46.914401Z","shell.execute_reply":"2025-06-16T13:54:46.921668Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"joblib.dump(label_encoder, 'label_encoder.joblib')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T13:54:47.14093Z","iopub.execute_input":"2025-06-16T13:54:47.141253Z","iopub.status.idle":"2025-06-16T13:54:47.150024Z","shell.execute_reply.started":"2025-06-16T13:54:47.14123Z","shell.execute_reply":"2025-06-16T13:54:47.148608Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"params = {\n    'objective': 'multiclass',\n    'num_class': 18,\n    'metric': ['multi_logloss', 'multi_error'],\n    'learning_rate': 0.01,\n    'feature_fraction': 0.8,\n    'bagging_fraction': 0.8,\n    'subsample_freq': 1,\n    'verbose': -1,\n}\n\noof = np.zeros(agg_train_df.shape[0], dtype=np.int32)\nkfold = StratifiedGroupKFold(n_splits=5, shuffle=True, random_state=42)\nfor fold, (trn_idx, val_idx) in enumerate(kfold.split(agg_train_df.index, y=agg_train_df.label_code, groups=agg_train_df.subject)):\n    trn_data = lgb.Dataset(agg_train_df.loc[trn_idx, feat_cols], agg_train_df.loc[trn_idx, 'label_code'])\n    val_data = lgb.Dataset(agg_train_df.loc[val_idx, feat_cols], agg_train_df.loc[val_idx, 'label_code'])\n\n    clf = lgb.train(params, trn_data, 10000, valid_sets=[trn_data, val_data], callbacks=[lgb.log_evaluation(100), lgb.early_stopping(400)])\n    clf.save_model(f'lgb_model_fold{fold}.txt')\n\n    val_pred = clf.predict(agg_train_df.loc[val_idx, feat_cols]).argmax(axis=-1)\n    val_true = agg_train_df.loc[val_idx, 'label_code'].values\n    print(f'Fold {fold} Cmpetition Score:', get_competition_score(label_encoder.inverse_transform(val_true), label_encoder.inverse_transform(val_pred)))\n\n    oof[val_idx] = val_pred","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T14:02:20.852155Z","iopub.execute_input":"2025-06-16T14:02:20.852463Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"oof_score = get_competition_score(\n    agg_train_df.label, label_encoder.inverse_transform(oof)\n)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print('5 Fold CV:', oof_score)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}