{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":82611,"databundleVersionId":9553358,"sourceType":"competition"},{"sourceId":9838119,"sourceType":"datasetVersion","datasetId":5844541}],"dockerImageVersionId":30776,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"<div style=\"text-align:center; border-radius:15px; padding:15px; margin:0; font-size:100%; font-family:Arial, sans-serif; background-color:#A8DADC; color:#1D3557; overflow:hidden; box-shadow:0 3px 6px rgba(0, 0, 0, 0.2);\">\n    <h2>BrisT1D Blood Glucose Prediction with TabNet</h2>\n</div>","metadata":{}},{"cell_type":"code","source":"!pip install -qq pytorch_tabnet\n\nfrom pytorch_tabnet.tab_model import TabNetRegressor","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tqdm import tqdm\nfrom itertools import product\n\nimport numpy as np\nimport pandas as pd\n\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nfrom sklearn.model_selection import GroupKFold\nfrom sklearn.impute import SimpleImputer\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"text-align:center; border-radius:15px; padding:15px; margin:0; font-size:100%; font-family:Arial, sans-serif; background-color:#A8DADC; color:#1D3557; overflow:hidden; box-shadow:0 3px 6px rgba(0, 0, 0, 0.2);\">\n    <h3>Data Variables</h3>\n</div>\n","metadata":{}},{"cell_type":"code","source":"# Define the hour and minute ranges for constructing feature column names\nhours = range(0, 6, 1)\nminutes = range(0, 60, 5)\n\ntarget_col = 'bg+1-00' # Target column name for prediction\ngroup_col = 'p_num'    # Column name for grouping (e.g., participant number)\ndate_col = 'time'      # Column name for time data\n\n# We only need the last 12 time intervals (1 hour)\nbg_cols   = [f'bg-{i}-{j:02d}' for i, j in product(hours, minutes)][:12]\ninsu_cols = [f'insulin-{i}-{j:02d}' for i, j in product(hours, minutes)][:12]\ncarb_cols = [f'carbs-{i}-{j:02d}' for i, j in product(hours, minutes)][:12]\nhr_cols   = [f'hr-{i}-{j:02d}' for i, j in product(hours, minutes)][:12]\nstep_cols = [f'steps-{i}-{j:02d}' for i, j in product(hours, minutes)][:12]\ncals_cols = [f'cals-{i}-{j:02d}' for i, j in product(hours, minutes)][:12]\n\nfeature_cols = bg_cols + insu_cols + carb_cols + hr_cols + step_cols + cals_cols","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"text-align:center; border-radius:15px; padding:15px; margin:0; font-size:100%; font-family:Arial, sans-serif; background-color:#A8DADC; color:#1D3557; overflow:hidden; box-shadow:0 3px 6px rgba(0, 0, 0, 0.2);\">\n    <h3>Loading and Preprocessing Data for Compatibility</h3>\n</div>\n","metadata":{"execution":{"iopub.status.busy":"2024-11-09T15:12:43.478314Z","iopub.execute_input":"2024-11-09T15:12:43.478984Z","iopub.status.idle":"2024-11-09T15:12:43.484947Z","shell.execute_reply.started":"2024-11-09T15:12:43.478944Z","shell.execute_reply":"2024-11-09T15:12:43.483728Z"}}},{"cell_type":"code","source":"df_train = pd.read_csv(\n    '/kaggle/input/brist1d/train.csv', \n    index_col='id', \n    parse_dates=['time'],\n)\n\ndf_test = pd.read_csv(\n    '/kaggle/input/brist1d/test.csv', \n    index_col='id', \n    parse_dates=['time'],\n)\n\ndf_subm = pd.read_csv(\n    \"/kaggle/input/brist1d/sample_submission.csv\",\n    index_col='id',\n)\n\n# Some frameworks may not handle column names with special characters like colons properly\ndf_train.columns = df_train.columns.str.replace(':', '-')\ndf_test.columns = df_test.columns.str.replace(':', '-')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"text-align:left; border-radius:15px; padding:15px; margin:0; font-size:100%; font-family:Arial, sans-serif; background-color:#A8DADC; color:#1D3557; overflow:hidden; box-shadow:0 3px 6px rgba(0, 0, 0, 0.2);\">\n    <h3>Interpolation Imputing</h3>\n    <div style=\"text-align:left; font-size:100%; margin-top:5px;\">Apply linear interpolation to fill missing values within each time series (e.g., blood glucose, insulin, etc.)</div>\n</div>\n","metadata":{}},{"cell_type":"code","source":"for colset in [bg_cols, insu_cols, carb_cols, hr_cols, step_cols, cals_cols]:\n    df_train[colset] = df_train[colset].interpolate(axis=1)\n    df_test[colset] = df_test[colset].interpolate(axis=1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"text-align:left; border-radius:15px; padding:15px; margin:0; font-size:100%; font-family:Arial, sans-serif; background-color:#A8DADC; color:#1D3557; overflow:hidden; box-shadow:0 3px 6px rgba(0, 0, 0, 0.2);\">\n    <h3>Mean Imputing</h3>\n    <div style=\"text-align:left; font-size:100%; margin-top:5px;\">This fits the imputer on the training data and fills missing values with the mean value</div>\n</div>\n","metadata":{}},{"cell_type":"code","source":"imputer = SimpleImputer()\n\ndf_train[feature_cols] = imputer.fit_transform(df_train[feature_cols])\ndf_test[feature_cols] = imputer.transform(df_test[feature_cols])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"text-align:left; border-radius:15px; padding:15px; margin:0; font-size:100%; font-family:Arial, sans-serif; background-color:#A8DADC; color:#1D3557; overflow:hidden; box-shadow:0 3px 6px rgba(0, 0, 0, 0.2);\">\n    <h3>Time Features</h3>\n    <div style=\"text-align:left; font-size:100%; margin-top:5px;\">Create cyclic time features using sine and cosine transformations for the 'hour' component of the date column\nThis helps encode the hour of the day in a way that captures its cyclical nature (e.g., 23:00 is close to 00:00)</div>\n</div>","metadata":{}},{"cell_type":"code","source":"df_train['sin_hour'] = np.sin(np.pi * df_train[date_col].dt.hour / 12)\ndf_train['cos_hour'] = np.cos(np.pi * df_train[date_col].dt.hour / 12)\n\ndf_test['sin_hour'] = np.sin(np.pi * df_test[date_col].dt.hour / 12)\ndf_test['cos_hour'] = np.cos(np.pi * df_test[date_col].dt.hour / 12)\n\nfeature_cols.extend(['sin_hour', 'cos_hour'])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"text-align:left; border-radius:15px; padding:15px; margin:0; font-size:100%; font-family:Arial, sans-serif; background-color:#A8DADC; color:#1D3557; overflow:hidden; box-shadow:0 3px 6px rgba(0, 0, 0, 0.2);\">\n    <h3>Grouped Features</h3>\n    <div style=\"text-align:left; font-size:100%; margin-top:5px;\">It is possible to specify attention groups (using grouped_features). Attention is done at the group level and not feature level. This is especially useful if a dataset has a lot of columns coming from on single source of data</div>\n</div>","metadata":{}},{"cell_type":"code","source":"grouped_features = []\n\n# Iterate through each set of related columns (e.g., blood glucose, insulin, etc.)\nfor colset in [bg_cols, insu_cols, carb_cols, hr_cols, step_cols, cals_cols]:\n    group_idxs = [idx for idx, col in enumerate(feature_cols) if col in colset]\n    grouped_features.append(group_idxs)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"text-align:center; border-radius:15px; padding:15px; margin:0; font-size:100%; font-family:Arial, sans-serif; background-color:#A8DADC; color:#1D3557; overflow:hidden; box-shadow:0 3px 6px rgba(0, 0, 0, 0.2);\">\n    <h3>Training & Inference</h3>\n</div>\n","metadata":{}},{"cell_type":"code","source":"X = df_train[feature_cols]\ny = df_train[[target_col]]\ngroups = df_train[group_col]\ncv = GroupKFold(5)\ndf_subm['bg+1:00'] = 0.0\n\nfor idx_train, idx_valid in cv.split(X, y, groups=groups):\n    \n    # Split the data into training and validation sets for the current fold\n    X_train, y_train = X.iloc[idx_train].to_numpy(), y.iloc[idx_train].to_numpy()\n    X_valid, y_valid = X.iloc[idx_valid].to_numpy(), y.iloc[idx_valid].to_numpy()\n    \n    # Initialize the TabNet Regressor model\n    reg = TabNetRegressor(\n        grouped_features=grouped_features, \n    )\n    \n    # Train the model using the training set and validate using the validation set\n    reg.fit(\n        X_train, y_train,\n        eval_set=[(X_valid, y_valid)],\n        eval_metric=['rmse'],\n        batch_size=1024,\n    )\n    \n    # Prepare the test data and make predictions\n    X_test = df_test[feature_cols].to_numpy()\n    \n    # Aggregate the predictions across the 5 folds (averaging for ensemble)\n    df_subm['bg+1:00'] += reg.predict(X_test)[:, 0] / 5\n    \ndf_subm.to_csv('submission.csv')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"text-align:center; border-radius:15px; padding:15px; margin:0; font-size:100%; font-family:Arial, sans-serif; background-color:#A8DADC; color:#1D3557; overflow:hidden; box-shadow:0 3px 6px rgba(0, 0, 0, 0.2);\">\n    <h3>Feature Importance</h3>\n</div>","metadata":{}},{"cell_type":"code","source":"feature_importances = pd.DataFrame({\n    'feature': feature_cols,\n    'importance': reg.feature_importances_\n})\n\nfeature_importances.sort_values(\n    by=\"importance\", ascending=False, inplace=True,\n)\n\nplt.figure(figsize = (12, 8))\nsns.barplot(\n    y=feature_importances[\"feature\"][:20], \n    x=feature_importances[\"importance\"][:20],\n)\nplt.title(\"Feature Importance\")\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}