Skip to content

Commit 00efd65

Browse files
committed
added a visualisation scatter plot ipython notebook for overall correlation for enotibit and bangle
1 parent 020c782 commit 00efd65

2 files changed

Lines changed: 207 additions & 30 deletions

File tree

scripts/evaluate_ml_models.ipynb

Lines changed: 87 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
},
1616
{
1717
"cell_type": "code",
18-
"execution_count": 13,
18+
"execution_count": 1,
1919
"metadata": {
2020
"execution": {
2121
"iopub.execute_input": "2026-05-19T18:35:31.922453Z",
@@ -62,7 +62,7 @@
6262
},
6363
{
6464
"cell_type": "code",
65-
"execution_count": 14,
65+
"execution_count": 2,
6666
"metadata": {
6767
"execution": {
6868
"iopub.execute_input": "2026-05-19T18:35:59.228007Z",
@@ -102,7 +102,7 @@
102102
},
103103
{
104104
"cell_type": "code",
105-
"execution_count": 15,
105+
"execution_count": 3,
106106
"metadata": {
107107
"execution": {
108108
"iopub.execute_input": "2026-05-19T18:36:00.269931Z",
@@ -123,29 +123,86 @@
123123
"Loaded 74 valid epochs (after excluding 6 bad subjects).\n",
124124
"Total unique subjects: 24\n",
125125
"Feature matrix shape: (74, 132) (features: 132, samples: 74)\n",
126-
"Running LOSO Cross-Validation... (This may take a minute)\n"
127-
]
128-
},
129-
{
130-
"ename": "KeyboardInterrupt",
131-
"evalue": "",
132-
"output_type": "error",
133-
"traceback": [
134-
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
135-
"\u001b[1;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)",
136-
"Cell \u001b[1;32mIn[15], line 78\u001b[0m\n\u001b[0;32m 70\u001b[0m n_inner \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mmin\u001b[39m(\u001b[38;5;241m5\u001b[39m, \u001b[38;5;28mlen\u001b[39m(np\u001b[38;5;241m.\u001b[39munique(groups_train)))\n\u001b[0;32m 71\u001b[0m grid \u001b[38;5;241m=\u001b[39m GridSearchCV(\n\u001b[0;32m 72\u001b[0m ridge_pipe,\n\u001b[0;32m 73\u001b[0m param_grid\u001b[38;5;241m=\u001b[39m{\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mmdl__alpha\u001b[39m\u001b[38;5;124m'\u001b[39m: RIDGE_ALPHAS},\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 76\u001b[0m n_jobs\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m\n\u001b[0;32m 77\u001b[0m )\n\u001b[1;32m---> 78\u001b[0m grid\u001b[38;5;241m.\u001b[39mfit(X_train, y_train, groups\u001b[38;5;241m=\u001b[39mgroups_train)\n\u001b[0;32m 79\u001b[0m ridge_pred \u001b[38;5;241m=\u001b[39m grid\u001b[38;5;241m.\u001b[39mpredict(X_test)\n\u001b[0;32m 80\u001b[0m best_alpha \u001b[38;5;241m=\u001b[39m grid\u001b[38;5;241m.\u001b[39mbest_params_[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mmdl__alpha\u001b[39m\u001b[38;5;124m'\u001b[39m]\n",
137-
"File \u001b[1;32mc:\\Users\\yasmi\\.conda\\Lib\\site-packages\\sklearn\\base.py:1151\u001b[0m, in \u001b[0;36m_fit_context.<locals>.decorator.<locals>.wrapper\u001b[1;34m(estimator, *args, **kwargs)\u001b[0m\n\u001b[0;32m 1144\u001b[0m estimator\u001b[38;5;241m.\u001b[39m_validate_params()\n\u001b[0;32m 1146\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m config_context(\n\u001b[0;32m 1147\u001b[0m skip_parameter_validation\u001b[38;5;241m=\u001b[39m(\n\u001b[0;32m 1148\u001b[0m prefer_skip_nested_validation \u001b[38;5;129;01mor\u001b[39;00m global_skip_validation\n\u001b[0;32m 1149\u001b[0m )\n\u001b[0;32m 1150\u001b[0m ):\n\u001b[1;32m-> 1151\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m fit_method(estimator, \u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n",
138-
"File \u001b[1;32mc:\\Users\\yasmi\\.conda\\Lib\\site-packages\\sklearn\\model_selection\\_search.py:933\u001b[0m, in \u001b[0;36mBaseSearchCV.fit\u001b[1;34m(self, X, y, groups, **fit_params)\u001b[0m\n\u001b[0;32m 931\u001b[0m refit_start_time \u001b[38;5;241m=\u001b[39m time\u001b[38;5;241m.\u001b[39mtime()\n\u001b[0;32m 932\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m y \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m--> 933\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mbest_estimator_\u001b[38;5;241m.\u001b[39mfit(X, y, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mfit_params)\n\u001b[0;32m 934\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m 935\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mbest_estimator_\u001b[38;5;241m.\u001b[39mfit(X, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mfit_params)\n",
139-
"File \u001b[1;32mc:\\Users\\yasmi\\.conda\\Lib\\site-packages\\sklearn\\base.py:1151\u001b[0m, in \u001b[0;36m_fit_context.<locals>.decorator.<locals>.wrapper\u001b[1;34m(estimator, *args, **kwargs)\u001b[0m\n\u001b[0;32m 1144\u001b[0m estimator\u001b[38;5;241m.\u001b[39m_validate_params()\n\u001b[0;32m 1146\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m config_context(\n\u001b[0;32m 1147\u001b[0m skip_parameter_validation\u001b[38;5;241m=\u001b[39m(\n\u001b[0;32m 1148\u001b[0m prefer_skip_nested_validation \u001b[38;5;129;01mor\u001b[39;00m global_skip_validation\n\u001b[0;32m 1149\u001b[0m )\n\u001b[0;32m 1150\u001b[0m ):\n\u001b[1;32m-> 1151\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m fit_method(estimator, \u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n",
140-
"File \u001b[1;32mc:\\Users\\yasmi\\.conda\\Lib\\site-packages\\sklearn\\pipeline.py:416\u001b[0m, in \u001b[0;36mPipeline.fit\u001b[1;34m(self, X, y, **fit_params)\u001b[0m\n\u001b[0;32m 390\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Fit the model.\u001b[39;00m\n\u001b[0;32m 391\u001b[0m \n\u001b[0;32m 392\u001b[0m \u001b[38;5;124;03mFit all the transformers one after the other and transform the\u001b[39;00m\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 413\u001b[0m \u001b[38;5;124;03m Pipeline with fitted steps.\u001b[39;00m\n\u001b[0;32m 414\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[0;32m 415\u001b[0m fit_params_steps \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_check_fit_params(\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mfit_params)\n\u001b[1;32m--> 416\u001b[0m Xt \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_fit(X, y, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mfit_params_steps)\n\u001b[0;32m 417\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m _print_elapsed_time(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mPipeline\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_log_message(\u001b[38;5;28mlen\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msteps) \u001b[38;5;241m-\u001b[39m \u001b[38;5;241m1\u001b[39m)):\n\u001b[0;32m 418\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_final_estimator \u001b[38;5;241m!=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpassthrough\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n",
141-
"File \u001b[1;32mc:\\Users\\yasmi\\.conda\\Lib\\site-packages\\sklearn\\pipeline.py:370\u001b[0m, in \u001b[0;36mPipeline._fit\u001b[1;34m(self, X, y, **fit_params_steps)\u001b[0m\n\u001b[0;32m 368\u001b[0m cloned_transformer \u001b[38;5;241m=\u001b[39m clone(transformer)\n\u001b[0;32m 369\u001b[0m \u001b[38;5;66;03m# Fit or load from cache the current transformer\u001b[39;00m\n\u001b[1;32m--> 370\u001b[0m X, fitted_transformer \u001b[38;5;241m=\u001b[39m fit_transform_one_cached(\n\u001b[0;32m 371\u001b[0m cloned_transformer,\n\u001b[0;32m 372\u001b[0m X,\n\u001b[0;32m 373\u001b[0m y,\n\u001b[0;32m 374\u001b[0m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[0;32m 375\u001b[0m message_clsname\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mPipeline\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[0;32m 376\u001b[0m message\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_log_message(step_idx),\n\u001b[0;32m 377\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mfit_params_steps[name],\n\u001b[0;32m 378\u001b[0m )\n\u001b[0;32m 379\u001b[0m \u001b[38;5;66;03m# Replace the transformer of the step with the fitted\u001b[39;00m\n\u001b[0;32m 380\u001b[0m \u001b[38;5;66;03m# transformer. This is necessary when loading the transformer\u001b[39;00m\n\u001b[0;32m 381\u001b[0m \u001b[38;5;66;03m# from the cache.\u001b[39;00m\n\u001b[0;32m 382\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msteps[step_idx] \u001b[38;5;241m=\u001b[39m (name, fitted_transformer)\n",
142-
"File \u001b[1;32mc:\\Users\\yasmi\\.conda\\Lib\\site-packages\\joblib\\memory.py:349\u001b[0m, in \u001b[0;36mNotMemorizedFunc.__call__\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m 348\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__call__\u001b[39m(\u001b[38;5;28mself\u001b[39m, \u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs):\n\u001b[1;32m--> 349\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfunc(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n",
143-
"File \u001b[1;32mc:\\Users\\yasmi\\.conda\\Lib\\site-packages\\sklearn\\pipeline.py:950\u001b[0m, in \u001b[0;36m_fit_transform_one\u001b[1;34m(transformer, X, y, weight, message_clsname, message, **fit_params)\u001b[0m\n\u001b[0;32m 948\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m _print_elapsed_time(message_clsname, message):\n\u001b[0;32m 949\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mhasattr\u001b[39m(transformer, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mfit_transform\u001b[39m\u001b[38;5;124m\"\u001b[39m):\n\u001b[1;32m--> 950\u001b[0m res \u001b[38;5;241m=\u001b[39m transformer\u001b[38;5;241m.\u001b[39mfit_transform(X, y, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mfit_params)\n\u001b[0;32m 951\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m 952\u001b[0m res \u001b[38;5;241m=\u001b[39m transformer\u001b[38;5;241m.\u001b[39mfit(X, y, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mfit_params)\u001b[38;5;241m.\u001b[39mtransform(X)\n",
144-
"File \u001b[1;32mc:\\Users\\yasmi\\.conda\\Lib\\site-packages\\sklearn\\utils\\_set_output.py:140\u001b[0m, in \u001b[0;36m_wrap_method_output.<locals>.wrapped\u001b[1;34m(self, X, *args, **kwargs)\u001b[0m\n\u001b[0;32m 138\u001b[0m \u001b[38;5;129m@wraps\u001b[39m(f)\n\u001b[0;32m 139\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mwrapped\u001b[39m(\u001b[38;5;28mself\u001b[39m, X, \u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs):\n\u001b[1;32m--> 140\u001b[0m data_to_wrap \u001b[38;5;241m=\u001b[39m f(\u001b[38;5;28mself\u001b[39m, X, \u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[0;32m 141\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(data_to_wrap, \u001b[38;5;28mtuple\u001b[39m):\n\u001b[0;32m 142\u001b[0m \u001b[38;5;66;03m# only wrap the first output for cross decomposition\u001b[39;00m\n\u001b[0;32m 143\u001b[0m return_tuple \u001b[38;5;241m=\u001b[39m (\n\u001b[0;32m 144\u001b[0m _wrap_data_with_container(method, data_to_wrap[\u001b[38;5;241m0\u001b[39m], X, \u001b[38;5;28mself\u001b[39m),\n\u001b[0;32m 145\u001b[0m \u001b[38;5;241m*\u001b[39mdata_to_wrap[\u001b[38;5;241m1\u001b[39m:],\n\u001b[0;32m 146\u001b[0m )\n",
145-
"File \u001b[1;32mc:\\Users\\yasmi\\.conda\\Lib\\site-packages\\sklearn\\base.py:918\u001b[0m, in \u001b[0;36mTransformerMixin.fit_transform\u001b[1;34m(self, X, y, **fit_params)\u001b[0m\n\u001b[0;32m 915\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfit(X, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mfit_params)\u001b[38;5;241m.\u001b[39mtransform(X)\n\u001b[0;32m 916\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m 917\u001b[0m \u001b[38;5;66;03m# fit method of arity 2 (supervised transformation)\u001b[39;00m\n\u001b[1;32m--> 918\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfit(X, y, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mfit_params)\u001b[38;5;241m.\u001b[39mtransform(X)\n",
146-
"File \u001b[1;32mc:\\Users\\yasmi\\.conda\\Lib\\site-packages\\sklearn\\utils\\_set_output.py:140\u001b[0m, in \u001b[0;36m_wrap_method_output.<locals>.wrapped\u001b[1;34m(self, X, *args, **kwargs)\u001b[0m\n\u001b[0;32m 138\u001b[0m \u001b[38;5;129m@wraps\u001b[39m(f)\n\u001b[0;32m 139\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mwrapped\u001b[39m(\u001b[38;5;28mself\u001b[39m, X, \u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs):\n\u001b[1;32m--> 140\u001b[0m data_to_wrap \u001b[38;5;241m=\u001b[39m f(\u001b[38;5;28mself\u001b[39m, X, \u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[0;32m 141\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(data_to_wrap, \u001b[38;5;28mtuple\u001b[39m):\n\u001b[0;32m 142\u001b[0m \u001b[38;5;66;03m# only wrap the first output for cross decomposition\u001b[39;00m\n\u001b[0;32m 143\u001b[0m return_tuple \u001b[38;5;241m=\u001b[39m (\n\u001b[0;32m 144\u001b[0m _wrap_data_with_container(method, data_to_wrap[\u001b[38;5;241m0\u001b[39m], X, \u001b[38;5;28mself\u001b[39m),\n\u001b[0;32m 145\u001b[0m \u001b[38;5;241m*\u001b[39mdata_to_wrap[\u001b[38;5;241m1\u001b[39m:],\n\u001b[0;32m 146\u001b[0m )\n",
147-
"File \u001b[1;32mc:\\Users\\yasmi\\.conda\\Lib\\site-packages\\sklearn\\impute\\_base.py:594\u001b[0m, in \u001b[0;36mSimpleImputer.transform\u001b[1;34m(self, X)\u001b[0m\n\u001b[0;32m 590\u001b[0m coordinates \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39mwhere(mask_valid_features\u001b[38;5;241m.\u001b[39mtranspose())[::\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m]\n\u001b[0;32m 592\u001b[0m X[coordinates] \u001b[38;5;241m=\u001b[39m values\n\u001b[1;32m--> 594\u001b[0m X_indicator \u001b[38;5;241m=\u001b[39m \u001b[38;5;28msuper\u001b[39m()\u001b[38;5;241m.\u001b[39m_transform_indicator(missing_mask)\n\u001b[0;32m 596\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28msuper\u001b[39m()\u001b[38;5;241m.\u001b[39m_concatenate_indicator(X, X_indicator)\n",
148-
"\u001b[1;31mKeyboardInterrupt\u001b[0m: "
126+
"Running LOSO Cross-Validation... (This may take a minute)\n",
127+
"\n",
128+
"--- PER-SUBJECT LOSO RESULTS (mean ± SD) ---\n",
129+
"Random Forest:\n",
130+
" -> MAE: 1.557 ± 0.511 METs [95% CI: 1.365 - 1.766]\n",
131+
" -> RMSE: 1.897 ± 0.617 METs\n",
132+
"\n",
133+
"Ridge Regression (nested alpha tuning):\n",
134+
" -> MAE: 2.463 ± 2.026 METs [95% CI: 1.761 - 3.338]\n",
135+
" -> RMSE: 3.171 ± 3.181 METs\n",
136+
"\n",
137+
"--- AGGREGATE LOSO RESULTS (for reference) ---\n",
138+
"Random Forest:\n",
139+
" -> MAE: 1.566 METs\n",
140+
" -> RMSE: 2.028 METs\n",
141+
" -> R²: 0.709\n",
142+
"\n",
143+
"Ridge Regression:\n",
144+
" -> MAE: 2.509 METs\n",
145+
" -> RMSE: 4.447 METs\n",
146+
" -> R²: -0.400\n",
147+
"\n",
148+
"\n",
149+
"==================================================\n",
150+
"Evaluating Scenario: EmotiBit (Consumer)\n",
151+
"==================================================\n",
152+
"Loaded 69 valid epochs (after excluding 6 bad subjects).\n",
153+
"Total unique subjects: 23\n",
154+
"Feature matrix shape: (69, 110) (features: 110, samples: 69)\n",
155+
"Running LOSO Cross-Validation... (This may take a minute)\n",
156+
"\n",
157+
"--- PER-SUBJECT LOSO RESULTS (mean ± SD) ---\n",
158+
"Random Forest:\n",
159+
" -> MAE: 1.508 ± 0.561 METs [95% CI: 1.288 - 1.741]\n",
160+
" -> RMSE: 1.818 ± 0.617 METs\n",
161+
"\n",
162+
"Ridge Regression (nested alpha tuning):\n",
163+
" -> MAE: 2.136 ± 2.511 METs [95% CI: 1.397 - 3.321]\n",
164+
" -> RMSE: 2.452 ± 2.504 METs\n",
165+
"\n",
166+
"--- AGGREGATE LOSO RESULTS (for reference) ---\n",
167+
"Random Forest:\n",
168+
" -> MAE: 1.489 METs\n",
169+
" -> RMSE: 1.912 METs\n",
170+
" -> R²: 0.744\n",
171+
"\n",
172+
"Ridge Regression:\n",
173+
" -> MAE: 1.902 METs\n",
174+
" -> RMSE: 2.784 METs\n",
175+
" -> R²: 0.457\n",
176+
"\n",
177+
"\n",
178+
"==================================================\n",
179+
"Evaluating Scenario: Bangle.js (Consumer)\n",
180+
"==================================================\n",
181+
"Loaded 74 valid epochs (after excluding 6 bad subjects).\n",
182+
"Total unique subjects: 24\n",
183+
"Feature matrix shape: (74, 110) (features: 110, samples: 74)\n",
184+
"Running LOSO Cross-Validation... (This may take a minute)\n",
185+
"\n",
186+
"--- PER-SUBJECT LOSO RESULTS (mean ± SD) ---\n",
187+
"Random Forest:\n",
188+
" -> MAE: 1.802 ± 1.153 METs [95% CI: 1.403 - 2.311]\n",
189+
" -> RMSE: 2.173 ± 1.347 METs\n",
190+
"\n",
191+
"Ridge Regression (nested alpha tuning):\n",
192+
" -> MAE: 2.311 ± 1.614 METs [95% CI: 1.751 - 3.000]\n",
193+
" -> RMSE: 2.695 ± 1.704 METs\n",
194+
"\n",
195+
"--- AGGREGATE LOSO RESULTS (for reference) ---\n",
196+
"Random Forest:\n",
197+
" -> MAE: 1.725 METs\n",
198+
" -> RMSE: 2.402 METs\n",
199+
" -> R²: 0.602\n",
200+
"\n",
201+
"Ridge Regression:\n",
202+
" -> MAE: 2.212 METs\n",
203+
" -> RMSE: 3.017 METs\n",
204+
" -> R²: 0.371\n",
205+
"\n"
149206
]
150207
}
151208
],
@@ -324,7 +381,7 @@
324381
},
325382
{
326383
"cell_type": "code",
327-
"execution_count": null,
384+
"execution_count": 4,
328385
"metadata": {
329386
"execution": {
330387
"iopub.execute_input": "2026-05-19T18:36:00.293917Z",
@@ -390,7 +447,7 @@
390447
"9 2018.0 4 100 2.556 4.075 9.844 2.225 \n",
391448
"10 2020.0 1 100 12.991 -10.016 -10.016 2.882 <<<\n",
392449
"11 2021.0 4 100 1.856 4.495 9.458 0.918 \n",
393-
"12 2022.0 3 100 2.028 7.255 12.643 0.704 \n",
450+
"12 2022.0 3 100 2.028 7.255 12.643 0.705 \n",
394451
"13 2024.0 3 100 1.131 4.078 8.765 1.551 \n",
395452
"14 2025.0 2 100 0.521 6.652 11.315 1.687 \n",
396453
"15 2026.0 3 100 1.569 5.582 9.012 1.090 \n",
@@ -472,7 +529,7 @@
472529
},
473530
{
474531
"cell_type": "code",
475-
"execution_count": null,
532+
"execution_count": 5,
476533
"metadata": {
477534
"execution": {
478535
"iopub.execute_input": "2026-05-19T18:39:11.587701Z",
@@ -561,7 +618,7 @@
561618
},
562619
{
563620
"cell_type": "code",
564-
"execution_count": 16,
621+
"execution_count": 6,
565622
"id": "f412a143",
566623
"metadata": {},
567624
"outputs": [

0 commit comments

Comments
 (0)