{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-11-01T17:41:07.070377Z","iopub.execute_input":"2023-11-01T17:41:07.07099Z","iopub.status.idle":"2023-11-01T17:41:07.107873Z","shell.execute_reply.started":"2023-11-01T17:41:07.07094Z","shell.execute_reply":"2023-11-01T17:41:07.106745Z"},"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pip install phik","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:07.110464Z","iopub.execute_input":"2023-11-01T17:41:07.111186Z","iopub.status.idle":"2023-11-01T17:41:21.383438Z","shell.execute_reply.started":"2023-11-01T17:41:07.111143Z","shell.execute_reply":"2023-11-01T17:41:21.381779Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Importing Libraries","metadata":{}},{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nimport glob\nimport math\nimport phik\nimport seaborn as sns\nimport lightgbm as lgb\nimport matplotlib.cm as cm\nimport matplotlib.colors as mcolors\nimport matplotlib.pyplot as plt\nimport matplotlib.gridspec as gridspec\n\nfrom tqdm.auto import tqdm\nfrom os import path\nfrom pathlib import Path\nfrom phik.phik import phik_matrix\nfrom phik.report import plot_correlation_matrix\nfrom sklearn.model_selection import GroupKFold\nfrom sklearn.base import clone\nfrom sklearn.metrics import average_precision_score","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:21.385469Z","iopub.execute_input":"2023-11-01T17:41:21.385952Z","iopub.status.idle":"2023-11-01T17:41:21.396072Z","shell.execute_reply.started":"2023-11-01T17:41:21.385909Z","shell.execute_reply":"2023-11-01T17:41:21.39475Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# utility functions\ndef get_num_cols(df):\n    numeric_columns = df.select_dtypes(include=[np.number]).columns\n    return numeric_columns\n\n\ndef factorize_column(column):\n    if column.dtype == \"category\" or column.dtype == \"object\":\n        return pd.factorize(column)[0]\n    return column","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:21.397604Z","iopub.execute_input":"2023-11-01T17:41:21.398087Z","iopub.status.idle":"2023-11-01T17:41:21.417811Z","shell.execute_reply.started":"2023-11-01T17:41:21.39804Z","shell.execute_reply":"2023-11-01T17:41:21.416151Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"root = \"/kaggle/input/tlvmc-parkinsons-freezing-gait-prediction/\"\n\ntrain_defog = glob.glob(os.path.join(root, \"train\", \"defog\", \"**\"))\ntrain_tdcsfog = glob.glob(os.path.join(root, \"train\", \"tdcsfog\", \"**\"))\ntest_defog = glob.glob(os.path.join(root, \"test\", \"defog\", \"**\"))\ntest_tdcsfog = glob.glob(os.path.join(root, \"test\", \"tdcsfog\", \"**\"))\n\nsubjects_df = pd.read_csv(os.path.join(root, \"subjects.csv\"))\n\ndaily_metadata = pd.read_csv(os.path.join(root, \"daily_metadata.csv\"))\ntdcsfog_metadata = pd.read_csv(os.path.join(root, \"tdcsfog_metadata.csv\"))\ndefog_metadata = pd.read_csv(os.path.join(root, \"defog_metadata.csv\"))\n\n#  events data which shows information of every FOG episodes\nevents_df = pd.read_csv(os.path.join(root, \"events.csv\"))","metadata":{"execution":{"iopub.status.busy":"2023-11-01T18:05:33.016961Z","iopub.execute_input":"2023-11-01T18:05:33.018398Z","iopub.status.idle":"2023-11-01T18:05:33.076591Z","shell.execute_reply.started":"2023-11-01T18:05:33.018348Z","shell.execute_reply":"2023-11-01T18:05:33.074969Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tdcsfog_metadata = tdcsfog_metadata.rename(\n    columns={\n        \"Subject\": \"subject\",\n        \"Visit\": \"visit\",\n        \"Test\": \"test\",\n        \"Medication\": \"medication\",\n    }\n)\ndefog_metadata = defog_metadata.rename(\n    columns={\"Subject\": \"subject\", \"Visit\": \"visit\", \"Medication\": \"medication\"}\n)\nsubjects_df = subjects_df.rename(\n    columns={\n        \"Subject\": \"subject\",\n        \"Visit\": \"visit\",\n        \"Age\": \"age\",\n        \"Sex\": \"sex\",\n        \"YearsSinceDx\": \"years_since_dx\",\n    }\n)\n\ndefog_metadata_subjects = subjects_df.merge(\n    defog_metadata, on=[\"subject\", \"visit\"], how=\"inner\"\n)\n\ntdcsfog_subjects = subjects_df.drop(\"visit\", axis=1)\ntdcsfog_metadata_subjects = tdcsfog_subjects.merge(\n    tdcsfog_metadata, on=[\"subject\"], how=\"inner\"\n)\ntdcsfog_metadata_subjects = tdcsfog_metadata_subjects.drop(\"visit\", axis=1)","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:21.473499Z","iopub.execute_input":"2023-11-01T17:41:21.474022Z","iopub.status.idle":"2023-11-01T17:41:21.49932Z","shell.execute_reply.started":"2023-11-01T17:41:21.473979Z","shell.execute_reply":"2023-11-01T17:41:21.4978Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data Exploration\n","metadata":{}},{"cell_type":"code","source":"subjects_df.head()","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:21.501123Z","iopub.execute_input":"2023-11-01T17:41:21.502168Z","iopub.status.idle":"2023-11-01T17:41:21.520626Z","shell.execute_reply.started":"2023-11-01T17:41:21.502123Z","shell.execute_reply":"2023-11-01T17:41:21.519002Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"PTR about subjects_df:\n- Visit Only available for subjects in the daily and defog datasets.\n- YearsSinceDx Years since Parkinson's diagnosis.\n- UPDRSIIIOn/UPDRSIIIOff Unified Parkinson's Disease Rating Scale score during on/off medication respectively.\n- NFOGQ Self-report FoG questionnaire score. See:\nhttps://pubmed.ncbi.nlm.nih.gov/19660949/","metadata":{}},{"cell_type":"code","source":"defog_metadata_subjects","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:21.52368Z","iopub.execute_input":"2023-11-01T17:41:21.524176Z","iopub.status.idle":"2023-11-01T17:41:21.55426Z","shell.execute_reply.started":"2023-11-01T17:41:21.524133Z","shell.execute_reply":"2023-11-01T17:41:21.552922Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tdcsfog_metadata_subjects","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:21.555675Z","iopub.execute_input":"2023-11-01T17:41:21.556042Z","iopub.status.idle":"2023-11-01T17:41:21.587164Z","shell.execute_reply.started":"2023-11-01T17:41:21.55601Z","shell.execute_reply":"2023-11-01T17:41:21.584916Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"The number of patients in DeFog metada:\" ,\n      len(pd.unique(defog_metadata_subjects[\"subject\"])))\nprint(\"The number of patients in TDCSFog metada:\" ,\n      len(pd.unique(tdcsfog_metadata_subjects[\"subject\"])))","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:21.588906Z","iopub.execute_input":"2023-11-01T17:41:21.589377Z","iopub.status.idle":"2023-11-01T17:41:21.599661Z","shell.execute_reply.started":"2023-11-01T17:41:21.589343Z","shell.execute_reply":"2023-11-01T17:41:21.597964Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"For analyzing the information of all 107 patients, both defog and tdcsfog metadata are joined.","metadata":{}},{"cell_type":"code","source":"full_metadata = pd.concat([defog_metadata_subjects, tdcsfog_metadata_subjects], axis=0)\n\nfull_metadata.drop([\"visit\", \"test\"], axis=1, inplace=True)\n\n#mapping binary values to 0 and 1\nfull_metadata[\"sex\"] = full_metadata[\"sex\"].map({\"F\": 0, \"M\": 1})\nfull_metadata[\"medication\"] = full_metadata[\"medication\"].map({\"on\": 0, \"off\": 1})\nfull_metadata","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:21.601863Z","iopub.execute_input":"2023-11-01T17:41:21.602397Z","iopub.status.idle":"2023-11-01T17:41:21.638229Z","shell.execute_reply.started":"2023-11-01T17:41:21.602325Z","shell.execute_reply":"2023-11-01T17:41:21.636769Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(full_metadata[[\"age\",\"years_since_dx\",\"UPDRSIII_On\",\"UPDRSIII_Off\",\"NFOGQ\"]].describe())\n\ndf=full_metadata[[\"age\",\"years_since_dx\",\"UPDRSIII_On\",\"UPDRSIII_Off\",\"NFOGQ\"]].copy()\nplt.figure(figsize=(8,5), dpi= 80)\nsns.boxplot( data=df, notch=False)\n\nplt.title('Box Plot of the full metadata', fontsize=10)\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:21.642517Z","iopub.execute_input":"2023-11-01T17:41:21.642985Z","iopub.status.idle":"2023-11-01T17:41:22.246242Z","shell.execute_reply.started":"2023-11-01T17:41:21.642951Z","shell.execute_reply":"2023-11-01T17:41:22.244686Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.style.use('default')\n\ntemp= full_metadata.copy()\ntemp.dropna(inplace=True)\ntemp=temp[temp['age']!=28]\ntemp.rename(columns={\"years_since_dx\":\"Years Since Diagnosis\"}, inplace=True)\ntemp['Age']=temp['age'].astype(\"int64\")\ntemp['Years Since Diagnosis']=temp['Years Since Diagnosis'].astype(\"int64\")\ncolumns = ['Age', 'Years Since Diagnosis']\n\ncolors_gender = ['#c2c2f0','#ffb3e6']\nfig, axes = plt.subplots(1, 3, figsize=(12, 4))\n\ncounts = temp[\"sex\"].value_counts()\ngender_labels=[\"Male\",\"Female\"]\naxes[0].pie(counts, labels=gender_labels,counterclock=False,startangle=90,autopct='%1.1f%%',\n                 colors=colors_gender, wedgeprops={'edgecolor': 'white', 'linewidth': 0.7})\naxes[0].set_title('Distribution of Sex', pad=20,fontdict={'fontsize': 10,'fontfamily':'Tahoma'})\n\nfor i, column in enumerate(columns):\n    # Get the minimum and maximum values of the column\n    min_value = temp[column].min()\n    max_value = temp[column].max()\n\n    min_value=5 * math.floor(min_value / 5)\n    # Create age ranges using pd.cut()\n    age_ranges = pd.cut(temp[column], bins=np.arange(min_value, max_value+5, 5), right=False,\n                        labels=[f'{i}-{i+5}' for i in range(min_value, max_value, 5)])\n\n    temp['Age Range'] = age_ranges\n\n    counts = temp['Age Range'].value_counts()\n    counts = counts.sort_values(ascending=False)\n    \n    # Sort the sizes_gender variable based on the sorting order of counts\n    sizes_gender = temp.groupby('Age Range')['sex'].value_counts().reindex(counts.index, level=0)\n    \n    gender_counts = sizes_gender.index.get_level_values('sex')\n\n    # Define the color map and assign colors based on gender counts\n    colors = [colors_gender[0] if gender == 1 else colors_gender[1] for gender in gender_counts]\n\n    wedges, texts, autotexts =axes[i+1].pie(counts, labels=counts.index,counterclock=False,startangle=90,\n                  autopct='%1.0f%%',wedgeprops={'edgecolor': 'white', 'linewidth': 0.5})\n    for autotext in autotexts:\n        autotext.set_horizontalalignment('center') \n        autotext.set_verticalalignment('center')  \n        autotext.set_position((1.5 * autotext.get_position()[0],1.5*autotext.get_position()[1]))\n        autotext.set_fontsize(8)\n        autotext.set_color('white')\n    \n    axes[i+1].set_title(f'Distribution of {column} and \\n Sex ', pad=15,  fontdict={'fontsize': 10,'fontfamily':'Tahoma'})\n    axes[i+1].pie(sizes_gender,colors=colors,radius=0.75,counterclock=False,startangle=90,\n               wedgeprops={'edgecolor': 'white', 'linewidth': 0.5})\n    \n    centre_circle = plt.Circle((0,0),0.55,fc='white')\n    axes[i+1].add_artist(centre_circle)\n    # Equal aspect ratio ensures that pie is drawn as a circle\n    axes[i+1].axis('equal')  \n\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:22.24846Z","iopub.execute_input":"2023-11-01T17:41:22.248913Z","iopub.status.idle":"2023-11-01T17:41:23.088287Z","shell.execute_reply.started":"2023-11-01T17:41:22.248879Z","shell.execute_reply":"2023-11-01T17:41:23.087085Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Key Insights:\n\n- Approximately 80% of the participants are men.\n- More than 56% of the participants are between 65-75 years old.\n- Around 60% of the participants were diagnosed 5-15 years ago.\n- Among participants aged between 80-85, the majority are women.","metadata":{}},{"cell_type":"code","source":"import seaborn as sns\nimport matplotlib.pyplot as plt\nimport matplotlib.cm as cm\nimport matplotlib.colors as mcolors\n\nfull_metadata[\"diff\"] = full_metadata[\"UPDRSIII_Off\"]-full_metadata[\"UPDRSIII_On\"]\n\nplt.figure(figsize=(6, 4))\n\n# Compute the correlation matrix\nnumberic_columns= get_num_cols(full_metadata)\ncorr_matrix = full_metadata[numberic_columns].corr()\n\n# Mask the diagonal elements\nmask = np.zeros_like(corr_matrix, dtype=bool)\nmask[np.triu_indices_from(mask)] = True\n\nheatmap = sns.heatmap(corr_matrix, cmap='RdBu', annot=True, fmt='.2f', linewidths=0.15,\n                      square=True,\n                      mask=mask\n                     )\nplt.title('Full metadata pairwise Correlation Heatmap', fontsize=9)\n\nheatmap.set_xticklabels(heatmap.get_xticklabels(), fontsize=8)\nheatmap.set_yticklabels(heatmap.get_yticklabels(), fontsize=8)\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:23.09426Z","iopub.execute_input":"2023-11-01T17:41:23.094729Z","iopub.status.idle":"2023-11-01T17:41:23.598374Z","shell.execute_reply.started":"2023-11-01T17:41:23.094692Z","shell.execute_reply":"2023-11-01T17:41:23.595305Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"A 'diff' column is added to display the difference between UPDRSIII_Off and UPDRSIII_On.\n\n- There is a relationship between diff and age, which will be analyzed.\n- Additionally, it seems reasonable to fill the missing values of UPDRSIII_Off (presented in the preprocessing part) since it has a strong relationship with UPDRSIII_On. It is also slightly correlated with years_since_dx, age, and sex.","metadata":{}},{"cell_type":"code","source":"temp = full_metadata[~full_metadata['UPDRSIII_On'].isna()].sort_values(\"diff\").copy()\n\nage = temp['age']\ndiff = temp['diff']\nfrequency = temp['age'].value_counts()\n\ncmap = plt.colormaps['Oranges']\n\n\nfig = plt.figure(figsize=(10, 4))\n# Define a custom grid layout for the subplots\ngrid = gridspec.GridSpec(1, 2, width_ratios=[1, 1])\n# Create the first subplot with a specific width\nax1 = plt.subplot(grid[0])\n\n\n# Create a subplot for the scatter plot or line plot\nplt.scatter(full_metadata['UPDRSIII_Off'], full_metadata['UPDRSIII_On'], c=full_metadata['age'], cmap='Oranges')\nplt.xlabel('UPDRSIII_Off')\nplt.ylabel('UPDRSIII_On')\nplt.title('Scatter Plot of UPDRSIII_Off vs UPDRSIII_On', fontsize=9, pad=15)\nplt.colorbar(label='Age')\n\nplt.plot([0, 90], [0, 90], 'r--')  # Add a red dashed line from (0, 0) to (90, 90)\n\n\n\nax2 = plt.subplot(grid[1])\nplt.subplot(1, 2, 2)\nm=plt.scatter(age, diff, c=frequency[age].values, cmap=cmap, s=frequency[age].values*5, alpha=0.8)\nplt.xlabel('age')\nplt.ylabel('diff')\nplt.title('Relationship between Age and the difference of\\n UPDRSIII_On and UPDRSIII_Off', fontsize=9, pad=15)\nplt.colorbar(mappable=m, label='Frequency')\n\n# Add a horizontal line at y=0\nplt.axhline(0, color='black', linestyle='--')  \n\nplt.tight_layout() \nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:23.600326Z","iopub.execute_input":"2023-11-01T17:41:23.60109Z","iopub.status.idle":"2023-11-01T17:41:24.478499Z","shell.execute_reply.started":"2023-11-01T17:41:23.601053Z","shell.execute_reply":"2023-11-01T17:41:24.477056Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style=\"text-align: justify\">As the plot above depicts, for the majority of cases, medication is effective in controlling UPDRSIII. However, in some cases, medication not only fails to be effective but also worsens the situation.<br>\nIn the next chart, the difference between UPDRSIII, when medication is on and when it is off, is calculated and compared to age. <b>For ages below 60, medication is almost universally effective</b>. However, for ages above 60, the effects vary greatly in a case-by-case manner. The most diversity is observed in the age range of 65-75 (as we saw before, 66% of patients are in this age group). In this age range, medication can either worsen the symptoms or be even more effective compared to other age ranges.</div>\n\n\nThe following trends can be observed with respect to the role of sex:\n","metadata":{}},{"cell_type":"code","source":"# women full metadata\ntemp = full_metadata.copy()\ntemp = temp[temp[\"sex\"]==0]\ntemp[\"diff\"]=temp[\"UPDRSIII_Off\"]-temp[\"UPDRSIII_On\"]\n\nprint(\"Average of UPDRSIII_Off in women: {:.2f}\".format(temp[\"UPDRSIII_Off\"].mean()))\nprint(\"Average of UPDRSIII_On in women: {:.2f}\".format(temp[\"UPDRSIII_On\"].mean()))\n\nprint(\"Average of difference between UPDRSIII_On and UPDRSIII_Off in women: {:.2f}\".format(temp[\"diff\"].mean()))\nprint(\"Ineffective medication cases in women: {:.2f} \".format((len(temp[temp[\"diff\"]<0])/len(temp))*100))","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:24.480523Z","iopub.execute_input":"2023-11-01T17:41:24.481062Z","iopub.status.idle":"2023-11-01T17:41:24.497255Z","shell.execute_reply.started":"2023-11-01T17:41:24.48101Z","shell.execute_reply":"2023-11-01T17:41:24.495659Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# men full metadata\ntemp = full_metadata.copy()\ntemp = temp[temp[\"sex\"]==1]\ntemp[\"diff\"]=temp[\"UPDRSIII_Off\"]-temp[\"UPDRSIII_On\"]\n\nprint(\"Average of UPDRSIII_Off in men: {:.2f}\".format(temp[\"UPDRSIII_Off\"].mean()))\nprint(\"Average of UPDRSIII_On in men: {:.2f}\".format(temp[\"UPDRSIII_On\"].mean()))\nprint(\"Average of difference between UPDRSIII_On and UPDRSIII_Off in men: {:.2f}\".format(temp[\"diff\"].mean()))\nprint(\"Ineffective medication cases in men: {:.2f}\".format((len(temp[temp[\"diff\"]<0])/len(temp))*100))","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:24.499367Z","iopub.execute_input":"2023-11-01T17:41:24.500193Z","iopub.status.idle":"2023-11-01T17:41:24.516013Z","shell.execute_reply.started":"2023-11-01T17:41:24.500137Z","shell.execute_reply":"2023-11-01T17:41:24.514104Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"This analysis reveals the following insights:\n\n* **Women generally exhibit a slightly better condition in Parkinson's disease.**\n* **On the other hand, medication tends to be trivially more effective in men.**","metadata":{}},{"cell_type":"markdown","source":"Now, we investigate a time series dataset that includes all three types of FOG, i.e., Start Hesitation, Turn, and Walking.","metadata":{}},{"cell_type":"code","source":"# get file series Id that includes all three FOG episodes\ndesired_id = events_df.groupby(\"Id\").filter(lambda x: all(item in x[\"Type\"].values for item in [\"StartHesitation\", \"Turn\", \"Walking\"]))[\"Id\"]\ndesired_id=pd.unique(desired_id)\n \nsample_Id=[]\nfor file in train_tdcsfog:\n        Id = file.split('/')[-1].split('.')[0]\n        if Id in desired_id:\n            sample_Id.append(Id)\n\nsample_train_tdcsfog_series = pd.read_csv(root + '/train/tdcsfog/' + str(sample_Id[0]) + '.csv')\nsample_train_tdcsfog_series","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:24.51796Z","iopub.execute_input":"2023-11-01T17:41:24.518653Z","iopub.status.idle":"2023-11-01T17:41:24.638288Z","shell.execute_reply.started":"2023-11-01T17:41:24.518609Z","shell.execute_reply":"2023-11-01T17:41:24.636905Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"This dataset is comprised of lower-back 3D accelerometer data which captures the following features related to FOG detection:\n\n* AccV: acceleration measured by a vertical sensor\n* AccML: acceleration measured by a mediolateral sensor\n* AccAP: acceleration measured by an anteroposterior sensor\n\n<img src=\"data:image/png;base64,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+OGH5d133xU3AlXaHYceeqj07NlTbr75ZilbtmzIeojmIoAAAggggAACCOS6AAGmXO9h2ocAAgiEQMCtANOaNWukV69eMmbMGNcCS7H8NWrUkCeeeEIuvfTS2Eu8RwABBBBAAAEEEEAgsAIEmALbdVQcAQQQQMAWcCPANHHiRLn++uvlzz//tIv19PWiiy6SESNGSOXKlT19DoUjgAACCCCAAAIIIJANAQJM2VDmGQgggAACngpkEmDat2+f3HnnnfLUU095Wsd4hdesWdOahnfsscfGu8w5BBBAAAEEEEAAAQQCI0CAKTBdRUURQAABBBIJpBtg2rlzp3Tu3FnefPPNREV7fr5SpUoyadIkadmypefP4gEIIIAAAggggAACCHglQIDJK1nKRQABBBDImkA6AaY9e/ZYO7u9//77WatnogeVKVNGpk6dKmeccUaiLJxHAAEEEEAAAQQQQMDXAsV9XTsqhwACCCCAgEcCN910k/ghuKTN27Fjh1xwwQXy3XffedRaikUAAQQQQAABBBBAwFsBAkze+lI6AggggIAPBYYNGyYvv/yyr2q2ceNG6dChg2zatMlX9aIyCCCAAAIIIIAAAggkI8AUuWSUyIMAAggg4GuBVKbIzZ8/X5o3by66/pIfU8eOHWXcuHF+rBp1QgABBBBAAAEEEEAgoQABpoQ0XEAAAQQQCIpAsgEm3THupJNOkq+//trXTXv33XelXbt2vq4jlUMAAQQQQAABBBBAIFqAKXLRGhwjgAACCOS0wIgRI3wfXNIO6Nmzp29HWOX0B4TGIYAAAggggAACCKQtQIApbTpuRAABBBAIksCuXbukf//+gajysmXLZOTIkYGoK5VEAAEEEEAAAQQQQEAFCDDxOUAAAQQQCIXAa6+9Jr/88ktg2vr444/L3r17A1NfKooAAggggAACCCAQbgECTOHuf1qPAAIIhEbg2WefDVRbf/75Z5k6dWqg6kxlEUAAAQQQQAABBMIrQIApvH1PyxFAAIHQCPz000+BWHsptkPGjh0be4r3CCCAAAIIIIAAAgj4UoAAky+7hUohgAACCLgpMGHCBDeLy1pZupvcnj17svY8HoQAAggggAACCCCAQLoCBJjSleM+BBBAAIHACHz++eeBqWt0RTdv3izz5s2LPsUxAggggAACCCCAAAK+FCDA5MtuoVIIIIAAAm4J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IIAAAggggAACGQgwgikDPG5FAAEE/CywYcMGqVu3rqxdu9bP1aRu/xWoVKmSLFmyRKpWrYoJAggggAACCCCAAAKBE2AEU+C6jAojgAACyQk8+uijBJeSo/JFro0bN0rv3r19URcqgQACCCCAAAIIIIBAqgKMYEpVjPwIIIBAAAR27dolhx12mPznP/8JQG2poi1QrFgx+fLLL+Wkk06yT/GKAAIIIIAAAggggEAgBBjBFIhuopIIIIBAagKzZs0iuJQamS9y60LsLMjui66gEggggAACCCCAAAIpChBgShGM7AgggEAQBKZPnx6EakqpUqXkqquukgYNGgSivtmo5OzZs2XkyJHZeBTPQAABBBBAAAEEEEDANQECTK5RUhACCCDgH4F58+b5pzJxalK9enXp37+/rFq1SkaPHi2///57nFzhPdW3b1/RNZlICCCAAAIIIIAAAggERYAAU1B6inoigAACKQh88803KeTOXtbmzZvLa6+9JitXrpT77rtPqlWrJosWLZL169dnrxIBeNIff/wh999/fwBqShURQAABBBBAAAEEEPh/AQJMfBIQQACBHBPYsGGDrFixwjetsqfBzZkzR3RtqCuuuEJKlizp1G/mzJnOMQf/E3j22Wdl4cKF/zvBEQIIIIAAAggggAACPhYo4eO6UTUEEEAAgTQE/DJ6SafBdevWTbp27WqNVErUlH/961+JLoX6/J49e+S2226TTz75JNQONB4BBBBAAAEEEEAgGAKMYApGP1FLBBBAIGmBog4w6TS4sWPH5pkGV1DlCTAl1vn000/lzTffTJyBKwgggAACCCCAAAII+ESAAJNPOoJqIIAAAm4JFEWASafBde7cWexpcJ06dcozDS5R29auXStLly5NdJnzRuCuu+6Sbdu2YYEAAggggAACCCCAgK8FCDD5unuoHAIIIJC6wPz581O/Kc07Dj30UBkwYICsXr3a2g2uWbNmKZXE6KXCuXSnvUceeaTwjORAAAEEEEAAAQQQQKAIBQgwFSE+j0YAAQTcFtixY4f8+OOPbhebr7xTTjlFxo0bZy0m3q9fP6latWq+PMmcIMCUjJLI448/LsuXL08uM7kQQAABBBBAAAEEECgCAQJMRYDOIxFAAAGvBL777jvRxaG9SKVLl5arr77amganO7917NgxqWlwBdWFAFNBOv+7poHD22+/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yvev3333nbRv31527tyZp67XX3+9LF68WK677jopVqxYnmv2m19//VUuuugiK0j1888/26d5RQABBBBAAAEEEEAgaQECTElTkREBBBBAwBbwywgmrwJM2s4aNWpYQabKlSvbzfb96xdffCFXXXVVvgW8NWA2cuRImTFjhjRu3DhhOzSo1qhRIxk8eLDs2rUrYT4uIIAAAggggAACCCAQK0CAKVaE9wgggAAChQr4YQSTjsapWbNmoXXNJIMGWyZNmiSlS5fOpJis3vvWW29Jjx494j6zRYsW1sLejzzyiJQrVy5uHl04vHfv3nLcccfJ559/HjcPJxFAAAEEEEAAAQQQiBUgwBQrwnsEEEAAgUIF/DCCqXr16lkJ/Jxxxhny2muvSfHiwfmW+cwzz4gGkeKlEiVKWAGkRYsWyfnnnx8vi3Xuxx9/lDPPPFNuuOEGWbt2bcJ8XEAAAQQQQAABBBBAQAWC89My/YUAAggg4BsBP4xg8nJ6XCz0xRdfLE8//XTsaV+/79u3r4waNSphHY844gh5//33rRFaepwo6dQ6XTD85Zdflkgkkigb5xFAAAEEEEAAAQRCLkCAKeQfAJqPAAIIpCPghxFM2QwwqdGtt94qGrQJUurSpYt8+OGHBVb5ggsuEB3N1LNnT9HRTfHS+vXrRRcLP+2000QXEychgAACCCCAAAIIIBArQIApVoT3CCCAAAIFCvzxxx+ybdu2AvNk42KtWrWy8Zg8z3jooYfk2muvzXPOz2/27Nkjl156qcyZM6fAaup6TEOGDLHWZ9J1mhKlmTNnStOmTaVPnz6ydevWRNk4jwACCCCAAAIIIBBCAQJMIex0mowAAghkIuCH6XFa/2yPYLLNXnrpJWnbtq391vevGghq166d/Prrr4XWVXeY053mnn/+eTnggAPi5teg1aBBg+SYY46RyZMnx83DSQQQQAABBBBAAIHwCRBgCl+f02IEEEAgIwE/TI/TBhRVgEmnkb355pty4oknZuSYzZt///13ayTT7t27C32s7s7XrVs30UW+r7zyyoT5V61aJX/961+lffv2osckBBBAAAEEEEAAgXALEGAKd//TegQQQCBlAb+MYCqKKXI2lk4p09E7Rx99tH3K9686vW3YsGFJ1/Pggw+WMWPGyOeffy4NGjRIeN+7775rjWZ68sknRUc3kRBAAAEEEEAA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\" alt=\"axis of movement\" width=\"500\">\nThese three characteristics are the main feautures to detect FOG.\n","metadata":{}},{"cell_type":"code","source":"sample_train_tdcsfog_series.describe()","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:24.639849Z","iopub.execute_input":"2023-11-01T17:41:24.640202Z","iopub.status.idle":"2023-11-01T17:41:24.683052Z","shell.execute_reply.started":"2023-11-01T17:41:24.640173Z","shell.execute_reply":"2023-11-01T17:41:24.681688Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Since the range of acceleration data is different, a suitable normalization process may improve the model performance (presented in the preprocessing part).","metadata":{}},{"cell_type":"code","source":"# Turn series\nsample_tdcsfog_Turn= sample_train_tdcsfog_series[sample_train_tdcsfog_series[\"Turn\"]==1]\n\n# StartHesitation series\nsample_tdcsfog_StartHesitation= sample_train_tdcsfog_series[sample_train_tdcsfog_series[\"StartHesitation\"]==1]\n\n# Walking series\nsample_tdcsfog_Walking= sample_train_tdcsfog_series[sample_train_tdcsfog_series[\"Walking\"]==1]\n\n# None Event series\nsample_tdcsfog_None= sample_train_tdcsfog_series[~((sample_train_tdcsfog_series[\"Walking\"]==1) |\n                                                    (sample_train_tdcsfog_series[\"StartHesitation\"]==1)|\n                                                    (sample_train_tdcsfog_series[\"Turn\"]==1))]\n\n# # Create the 4*2 grid of subplots\ngrid = (4, 2)\nfig = plt.figure(figsize=(10, 5))\n\n# # Create the first pie chart spanning cells (1,1) and (2,1) and (3,1) and(4,1)\nax1 = plt.subplot2grid(grid, (0, 0), rowspan=4, colspan=1)\n\nax1.plot(sample_train_tdcsfog_series[\"Time\"], sample_train_tdcsfog_series[\"AccV\"], label=\"AccV\")\nax1.plot(sample_train_tdcsfog_series[\"Time\"], sample_train_tdcsfog_series[\"AccML\"], label=\"AccML\")\nax1.plot(sample_train_tdcsfog_series[\"Time\"], sample_train_tdcsfog_series[\"AccAP\"], label=\"AccAP\")\n\nax1.legend()\n\nax1.set_title(\"TDCSFog series sample\")\n\nax2 = plt.subplot2grid(grid, (0, 1))\n\n# Plot sample_tdcsfog_Turn in the second column\nax2.plot(sample_tdcsfog_Turn[\"Time\"], sample_tdcsfog_Turn[[\"AccV\", \"AccML\", \"AccAP\"]])\nax2.set_title(\"Turn\")\n\nax3 = plt.subplot2grid(grid, (1, 1))\n# Plot sample_tdcsfog_StartHesitation in the second column\nax3.plot(sample_tdcsfog_StartHesitation[\"Time\"], sample_tdcsfog_StartHesitation[[\"AccV\", \"AccML\", \"AccAP\"]])\nax3.set_title(\"StartHesitation\")\n\nax4 = plt.subplot2grid(grid, (2, 1))\n# Plot sample_tdcsfog_Walking in the second column\nax4.plot(sample_tdcsfog_Walking[\"Time\"], sample_tdcsfog_Walking[[\"AccV\", \"AccML\", \"AccAP\"]])\nax4.set_title(\"Walking\")\n\nax4 = plt.subplot2grid(grid, (3, 1))\n# Plot sample_tdcsfog_None in the second column\nax4.plot(sample_tdcsfog_None[\"Time\"], sample_tdcsfog_None[[\"AccV\", \"AccML\", \"AccAP\"]])\nax4.set_title(\"None\")\n\n# Adjust spacing between subplots\nplt.tight_layout()\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:24.685158Z","iopub.execute_input":"2023-11-01T17:41:24.685698Z","iopub.status.idle":"2023-11-01T17:41:26.088964Z","shell.execute_reply.started":"2023-11-01T17:41:24.685653Z","shell.execute_reply":"2023-11-01T17:41:26.087524Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"In a particular time series, we observe that the variation of acceleration data during the Turn episode is at its `maximum` , which is a reasonable expectation.\nHowever, what makes the prediction challenging is the observation of non-trivial variations even in the absence of Turn, Walking, or Start Hesitation episodes. This variability in the data adds complexity to the prediction task.","metadata":{}},{"cell_type":"markdown","source":"Counts of FoG events for different age ranges in the dataset. This will help us to understand if there is any correlation between age and the frequency of FoG events. We can use the pd.qcut() function to bin the age column into different age ranges, then count the number of FoG events in each range and plot it.","metadata":{}},{"cell_type":"code","source":"tdcsfog_metadata['dataset'] = 'tdcsfog'\ndefog_metadata['dataset'] = 'defog'\n\nfull_metadata_plot = pd.concat([tdcsfog_metadata, defog_metadata])\nevents_data = events_df\nevents_data['event_duration'] = events_df['Completion'] - events_df['Init']\n\nall_metadata_df = events_data[['Id', 'Type', 'Kinetic', 'event_duration']] \\\n                            .merge(full_metadata_plot, on='Id') \\\n                            .merge(subjects_df.drop('visit', axis=1), on='subject')\nall_metadata_df\n","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:26.09081Z","iopub.execute_input":"2023-11-01T17:41:26.091885Z","iopub.status.idle":"2023-11-01T17:41:26.142246Z","shell.execute_reply.started":"2023-11-01T17:41:26.091848Z","shell.execute_reply":"2023-11-01T17:41:26.140963Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"all_metadata_df[\"sex\"] = all_metadata_df[\"sex\"].map({\"F\": 0, \"M\": 1})\nall_metadata_df[\"medication\"] = all_metadata_df[\"medication\"].map({\"on\": 0, \"off\": 1})\nall_metadata_df","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:26.1438Z","iopub.execute_input":"2023-11-01T17:41:26.144127Z","iopub.status.idle":"2023-11-01T17:41:26.183303Z","shell.execute_reply.started":"2023-11-01T17:41:26.144098Z","shell.execute_reply":"2023-11-01T17:41:26.181808Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# bin the Age column based on quantiles\nall_metadata_df['age_bin'] = pd.qcut(all_metadata_df['age'], q=5)","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:26.18519Z","iopub.execute_input":"2023-11-01T17:41:26.186918Z","iopub.status.idle":"2023-11-01T17:41:26.197806Z","shell.execute_reply.started":"2023-11-01T17:41:26.186858Z","shell.execute_reply":"2023-11-01T17:41:26.196313Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Plot the frequency of FoG events of each Type for different age ranges\nplt.figure(figsize=(15, 14))\nfor i, age_bin in enumerate(all_metadata_df.age_bin.unique(), 1):\n    plt.subplot(3, 3, i)\n    sns.barplot(\n        x=all_metadata_df[all_metadata_df.age_bin == age_bin].Type\n                                        .value_counts(normalize=True).index,\n        y=all_metadata_df[all_metadata_df.age_bin == age_bin].Type\n                                        .value_counts(normalize=True))\n    plt.ylabel('The frequency of FoG events')\n    plt.title(f\"Age in range {age_bin}\")\n    \n    # Add frequency values on top of the bars\n    for index, value in enumerate(\n                all_metadata_df[all_metadata_df.age_bin == age_bin].Type\n                                            .value_counts(normalize=True)):\n        plt.annotate(f\"{value * 100:.1f}%\", xy=(index, value),\n                                    ha='center', va='bottom')\nplt.subplots_adjust(wspace=0.3, hspace=0.2)\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:26.199664Z","iopub.execute_input":"2023-11-01T17:41:26.200034Z","iopub.status.idle":"2023-11-01T17:41:27.321656Z","shell.execute_reply.started":"2023-11-01T17:41:26.200002Z","shell.execute_reply":"2023-11-01T17:41:27.320819Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"frequency of FoG events of each Type for male and female patients in the dataset.","metadata":{}},{"cell_type":"code","source":"# Plot the frequency of FoG events of each Type for male and female patients\nplt.figure(figsize=(12, 5))\ngender_dict = {0: 'Female', 1: 'Male'}\nfor i, gender in enumerate(all_metadata_df.sex.unique(), 1):\n    plt.subplot(1, 2, i)\n    sns.barplot(\n        x=all_metadata_df[all_metadata_df.sex == gender].Type\n                                .value_counts(normalize=True).index,\n        y=all_metadata_df[all_metadata_df.sex == gender].Type\n                                .value_counts(normalize=True))\n    plt.ylabel('The frequency of FoG events')\n    plt.title(f\"Gender = {gender_dict[gender]}\")\n    \n    # Add frequency values on top of the bars\n    for index, value in enumerate(\n            all_metadata_df[all_metadata_df.sex == gender].Type\n                                    .value_counts(normalize=True)):\n        plt.annotate(f\"{value * 100:.1f}%\", xy=(index, value),\n                                    ha='center', va='bottom')\nplt.subplots_adjust(wspace=0.4)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:27.323049Z","iopub.execute_input":"2023-11-01T17:41:27.323578Z","iopub.status.idle":"2023-11-01T17:41:27.875419Z","shell.execute_reply.started":"2023-11-01T17:41:27.323533Z","shell.execute_reply":"2023-11-01T17:41:27.874063Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Plot the counts of FoG events for different age ranges\nplt.figure(figsize=(12, 5))\nmed_dict = {0: 'Medication status: off', 1: 'Medication status: on'}\nfor i, med_status in enumerate(all_metadata_df.medication.unique(), 1):\n    plt.subplot(1, 2, i)\n    sns.barplot(\n        x=all_metadata_df[all_metadata_df.medication == med_status].Type\n                                        .value_counts(normalize=True).index,\n        y=all_metadata_df[all_metadata_df.medication == med_status].Type\n                                        .value_counts(normalize=True))\n    plt.ylabel('The frequency of FoG events')\n    plt.title(f\"{med_dict[med_status]}\")\n    \n    # Add frequency values on top of the bars\n    for index, value in enumerate(\n            all_metadata_df[all_metadata_df.medication == med_status].Type\n                                            .value_counts(normalize=True)):\n        plt.annotate(f\"{value * 100:.1f}%\", xy=(index, value),\n                                    ha='center', va='bottom')\nplt.subplots_adjust(wspace=0.4)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:27.876997Z","iopub.execute_input":"2023-11-01T17:41:27.877584Z","iopub.status.idle":"2023-11-01T17:41:28.755243Z","shell.execute_reply.started":"2023-11-01T17:41:27.877532Z","shell.execute_reply":"2023-11-01T17:41:28.753687Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## The train Datasets exploring","metadata":{}},{"cell_type":"markdown","source":"### The lab data (`tdcsfog` Dataset)","metadata":{}},{"cell_type":"markdown","source":"The tDCS FOG (tdcsfog) dataset comprises data series collected in the lab, as subjects completed a FOG-provoking protocol.\n\nLet's select only 500 files from the `tdcsfog` folder and take a look at the dataset profile report and correlation matrix.","metadata":{}},{"cell_type":"code","source":"# Read 500 files of the tdcsfog metadata (the total number of files is 833)\ntdcsfog_files = [f'{root}train/tdcsfog/{id}.csv' for id in \\\n                                         tdcsfog_metadata.Id.to_list()[:501]]\n\ntdcsfog_data = pd.concat([pd.read_csv(file) for file in tdcsfog_files])","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:28.756756Z","iopub.execute_input":"2023-11-01T17:41:28.757124Z","iopub.status.idle":"2023-11-01T17:41:35.608325Z","shell.execute_reply.started":"2023-11-01T17:41:28.757094Z","shell.execute_reply":"2023-11-01T17:41:35.607029Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mask = np.triu(np.ones_like(tdcsfog_data.corr(), dtype=bool))\nfig, ax = plt.subplots(figsize=(7, 5))\nsns.heatmap(tdcsfog_data.corr(), mask=mask, annot=True, cmap='coolwarm',\n                linewidths=0.2, annot_kws={\"size\": 7}, rasterized=True)\nplt.xticks(rotation=35)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:35.610534Z","iopub.execute_input":"2023-11-01T17:41:35.610927Z","iopub.status.idle":"2023-11-01T17:41:37.562448Z","shell.execute_reply.started":"2023-11-01T17:41:35.610895Z","shell.execute_reply":"2023-11-01T17:41:37.560901Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"phik_overview = tdcsfog_data.phik_matrix(\n                            interval_cols=['AccV', 'AccML', 'AccAP','Time'])\n\nplot_correlation_matrix(phik_overview.values, x_labels=phik_overview.columns,\n                        y_labels=phik_overview.index, vmin=0, vmax=1, \n                        color_map='Blues', title=r'correlation matrix $\\phi_K$',\n                        figsize=(7, 5))\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:41:37.564658Z","iopub.execute_input":"2023-11-01T17:41:37.56504Z","iopub.status.idle":"2023-11-01T17:42:10.850866Z","shell.execute_reply.started":"2023-11-01T17:41:37.565008Z","shell.execute_reply":"2023-11-01T17:42:10.849828Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"From dataset report and correlation matrix, it can be concluded that:\n\n  - There are no missing values and duplicate rows detected in the dataset.\n  - As can be seen from the profiling report, all target variables are highly imbalanced, especially `StartHesitation` (78.5%) and `Walking` (80.1%).\n  - Based on histograms and skewness values the distributions of the `AccAP` and `AccV` columns are moderately left-skewed, the `AccML` column seems to have a close to normal distribution.\n  - The `AccAP` column have a kurtosis value of less than 3, which indicates that the column is platikurtic. Meanwhile, the `AccV` column has a kurtosis value of more than 3, which indicates that the column is leptokurtic. And  a kurtosis value of the`AccML` column is close to 3, which is recognized as mesokurtic column.\n  - As can be seen from Pearson's and Phik correlation matrices `Time` column have a moderate positive correlation with two target variables `Turn`, `Walking` and variable of anteroposterior acceleration measurements. However, between the target variable `StartHesitation` and other variables there is no strong or moderate correlation.","metadata":{}},{"cell_type":"markdown","source":"#### Plotting the acceleration measurements for events of each Type","metadata":{}},{"cell_type":"code","source":"# Read one file of the tdcsfog train data with event of Turn type\ntdcsfog_files_turn = [f'{root}train/tdcsfog/{id}.csv' for id in \\\n                              tdcsfog_metadata.Id.to_list()[16:17]]\n\ntdcsfog_data_turn = pd.concat([pd.read_csv(file) for file in tdcsfog_files_turn])\n\n# Read one file of the tdcsfog train data with event of Walking type\ntdcsfog_files_walk = [f'{root}train/tdcsfog/{id}.csv' for id in \\\n                              tdcsfog_metadata.Id.to_list()[19:20]]\n\ntdcsfog_data_walk = pd.concat([pd.read_csv(file) for file in tdcsfog_files_walk])\n\n# Read one file of the tdcsfog train data with event of StartHesitation type\ntdcsfog_files_hes = [f'{root}train/tdcsfog/{id}.csv' for id in \\\n                             tdcsfog_metadata.Id.to_list()[77:78]]\n\ntdcsfog_data_hes = pd.concat([pd.read_csv(file) for file in tdcsfog_files_hes])","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:42:10.85221Z","iopub.execute_input":"2023-11-01T17:42:10.853041Z","iopub.status.idle":"2023-11-01T17:42:10.980085Z","shell.execute_reply.started":"2023-11-01T17:42:10.853006Z","shell.execute_reply":"2023-11-01T17:42:10.978679Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Since the series in the `tdcsfog` dataset are recorded at a frequency of 128Hz (128 time steps per second), we can plot the acceleration measurements for each axis (V - vertical, ML - mediolateral, AP - anteroposterior) using a rolling mean method with a window size of 128. This helps to smooth out fluctuations in the data and provides a better representation of the overall trend of the acceleration measurements over time.","metadata":{}},{"cell_type":"markdown","source":"Let's plot the overall trends of acceleration measurements for events of each Type.","metadata":{}},{"cell_type":"code","source":"# Plot the overall trends of acceleration measurements for events of each Type\nplt.figure(figsize=(14, 12))\n\ntypes_dict = {1: 'Turn', 2: 'Walking', 3: 'StartHesitation'}\n\nfor i, data in enumerate(\n            [tdcsfog_data_turn, tdcsfog_data_walk, tdcsfog_data_hes], 1):\n    plt.subplot(2, 2, i)\n    window_size = 128\n    accv_rolling_mean = data[\"AccV\"].rolling(window_size).mean()\n    accap_rolling_mean = data[\"AccAP\"].rolling(window_size).mean()\n    accml_rolling_mean = data[\"AccML\"].rolling(window_size).mean()\n\n    sns.lineplot(x=data.Time, y=accv_rolling_mean)\n    sns.lineplot(x=data.Time, y=accap_rolling_mean)\n    sns.lineplot(x=data.Time, y=accml_rolling_mean)\n    plt.title(f'The trend of acceleration measurements (\"{types_dict[i]}\" event)')\n    plt.xlabel('Time')\n    plt.ylabel('Acceleration value (m/s^2)')\n\nplt.legend(['Anteroposterior', 'Mediolateral', 'Vertical'], loc='upper left',\n               bbox_to_anchor=(2.3, 2.1), handlelength=0,\n               shadow=True, labelcolor=['orange', 'green', 'blue'])\nplt.subplots_adjust(wspace=0.3, hspace=0.2)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:42:10.98251Z","iopub.execute_input":"2023-11-01T17:42:10.983495Z","iopub.status.idle":"2023-11-01T17:42:13.705104Z","shell.execute_reply.started":"2023-11-01T17:42:10.983448Z","shell.execute_reply":"2023-11-01T17:42:13.703864Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### The home data (`DeFOG` Dataset)","metadata":{}},{"cell_type":"markdown","source":"The DeFOG (defog) dataset comprises data series collected in the subject's home, as subjects completed a FOG-provoking protocol.\n\nAs we know from the data descriptions, the series in the `notype` folder are from the DeFOG dataset but lack event-type annotations. Let's create a list of indices that correspond to the notype series IDs. Using this list, we can separate the `defog_metadata` set into two metadata sets: one for notype and one for defog series.","metadata":{}},{"cell_type":"code","source":"# Creating a list of indices that correspond to the notype series IDs in the defog_metadata\nnotype_idx = [0, 4, 13, 15, 17, 19, 20, 22, 25, 27, 30, 31, 32, 34, 36, 40, 42,\n              53, 54, 55, 58, 60, 62, 66, 67, 73, 74, 76, 79, 83, 84, 88, 89, 94,\n              96, 97, 98, 101, 102, 105, 113, 114, 115, 121, 124, 126]\n\n# Separating the defog_metadata\ndefog_metadata_only = defog_metadata[~defog_metadata.index.isin(notype_idx)].copy()\nnotype_metadata = defog_metadata[defog_metadata.index.isin(notype_idx)].copy()","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:42:13.706738Z","iopub.execute_input":"2023-11-01T17:42:13.707727Z","iopub.status.idle":"2023-11-01T17:42:13.718841Z","shell.execute_reply.started":"2023-11-01T17:42:13.707691Z","shell.execute_reply":"2023-11-01T17:42:13.717531Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Read one file of the defog metadata (the total number of files is 91)\ndefog_files = [f'{root}train/defog/{id}.csv' for id in \\\n                               defog_metadata_only.Id.to_list()[:1]]\n\ndefog_data = pd.concat([pd.read_csv(file) for file in defog_files])","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:42:13.720847Z","iopub.execute_input":"2023-11-01T17:42:13.721639Z","iopub.status.idle":"2023-11-01T17:42:13.913222Z","shell.execute_reply.started":"2023-11-01T17:42:13.721593Z","shell.execute_reply":"2023-11-01T17:42:13.912187Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pd.concat([defog_metadata[defog_metadata.Id == '02ea782681'],\n           events_data[events_data.Id == '02ea782681']], axis=1)","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:42:13.91508Z","iopub.execute_input":"2023-11-01T17:42:13.915838Z","iopub.status.idle":"2023-11-01T17:42:13.943234Z","shell.execute_reply.started":"2023-11-01T17:42:13.915793Z","shell.execute_reply":"2023-11-01T17:42:13.941484Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"defog_data_valid = defog_data.loc[ \\\n                        (defog_data.Valid == True) & (defog_data.Task == True)]\ndefog_data_valid.shape","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:42:13.944837Z","iopub.execute_input":"2023-11-01T17:42:13.946942Z","iopub.status.idle":"2023-11-01T17:42:13.961331Z","shell.execute_reply.started":"2023-11-01T17:42:13.946897Z","shell.execute_reply":"2023-11-01T17:42:13.960039Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Ploting the acceleration measurements for each axis","metadata":{}},{"cell_type":"markdown","source":"Since the series in the `defog` dataset are recorded at a frequency of 100Hz (100 time steps per second), we can plot the smoothed acceleration measurements for each axis (V - vertical, ML - mediolateral, AP - anteroposterior) using a rolling window technique with a window size of 100 and see the overall trend of acceleration measurements for each axis.","metadata":{}},{"cell_type":"code","source":"# Plot the overall trend of acceleration measurements for each axis\nplt.figure(figsize=(14, 5))\n\ndefogdata_dict = {1: 'All defogdata', 2: 'Valid defog data'}\n\nfor i, data in enumerate([defog_data, defog_data_valid], 1):\n    plt.subplot(1, 2, i)\n    window_size = 100\n    accv_rolling_mean = data[\"AccV\"].rolling(window_size).mean()\n    accap_rolling_mean = data[\"AccAP\"].rolling(window_size).mean()\n    accml_rolling_mean = data[\"AccML\"].rolling(window_size).mean()\n\n    sns.lineplot(x=data.Time, y=accv_rolling_mean)\n    sns.lineplot(x=data.Time, y=accap_rolling_mean)\n    sns.lineplot(x=data.Time, y=accml_rolling_mean)\n    plt.title(f'The trend of acceleration measurements ({defogdata_dict[i]})')\n    plt.xlabel('Time')\n    plt.ylabel('Acceleration value (g)')\n\nplt.legend(['Mediolateral', 'Anteroposterior', 'Vertical'], loc='upper left',\n               bbox_to_anchor=(1.05, 1), shadow=True, handlelength=0,\n               labelcolor=['green', 'orange', 'blue'])\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:42:13.963075Z","iopub.execute_input":"2023-11-01T17:42:13.964035Z","iopub.status.idle":"2023-11-01T17:42:18.5445Z","shell.execute_reply.started":"2023-11-01T17:42:13.963997Z","shell.execute_reply":"2023-11-01T17:42:18.543079Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### The daily data (`Daily Living` dataset)","metadata":{}},{"cell_type":"markdown","source":"The Daily Living (daily) dataset comprises one week of continuous 24/7 recordings from sixty-five subjects. Forty-five subjects exhibit FOG symptoms and also have series in the defog dataset, while the other twenty subjects do not exhibit FOG symptoms and do not have series elsewhere in the data.\n","metadata":{}},{"cell_type":"code","source":"daily_metadata.Id.to_list()","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:42:18.54604Z","iopub.execute_input":"2023-11-01T17:42:18.546372Z","iopub.status.idle":"2023-11-01T17:42:18.55703Z","shell.execute_reply.started":"2023-11-01T17:42:18.546344Z","shell.execute_reply":"2023-11-01T17:42:18.555673Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Read one file of the daily metadata (the total number of files is 65)\ndaily_files = [f'{root}unlabeled/{id}.parquet' for id in \\\n                                       daily_metadata.Id.to_list()[:1]]\n\ndaily_data = pd.concat([pd.read_parquet(file) for file in daily_files])\n\n","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:42:18.559173Z","iopub.execute_input":"2023-11-01T17:42:18.560015Z","iopub.status.idle":"2023-11-01T17:42:24.489008Z","shell.execute_reply.started":"2023-11-01T17:42:18.559981Z","shell.execute_reply":"2023-11-01T17:42:24.487153Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"d = pd.read_parquet(daily_files[0])\nd","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:42:24.491019Z","iopub.execute_input":"2023-11-01T17:42:24.491427Z","iopub.status.idle":"2023-11-01T17:42:28.480131Z","shell.execute_reply.started":"2023-11-01T17:42:24.491393Z","shell.execute_reply":"2023-11-01T17:42:28.478798Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"defog_data.describe(include='float64').T","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:42:28.481606Z","iopub.execute_input":"2023-11-01T17:42:28.482996Z","iopub.status.idle":"2023-11-01T17:42:28.538704Z","shell.execute_reply.started":"2023-11-01T17:42:28.482929Z","shell.execute_reply":"2023-11-01T17:42:28.537277Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"markdown","source":"## Data Preprocessing","metadata":{}},{"cell_type":"code","source":"print(\"Null values in Subjects dataset:\")\nsubjects_df.isna().sum()","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:42:28.552909Z","iopub.execute_input":"2023-11-01T17:42:28.556589Z","iopub.status.idle":"2023-11-01T17:42:28.578284Z","shell.execute_reply.started":"2023-11-01T17:42:28.556506Z","shell.execute_reply":"2023-11-01T17:42:28.576845Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"full_metadata","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:42:28.580269Z","iopub.execute_input":"2023-11-01T17:42:28.581074Z","iopub.status.idle":"2023-11-01T17:42:28.617978Z","shell.execute_reply.started":"2023-11-01T17:42:28.581028Z","shell.execute_reply":"2023-11-01T17:42:28.616674Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"The null percentage of UPDRSIII_Off:{:.2f}%\".format(full_metadata[\"UPDRSIII_Off\"].isna().sum()/len(full_metadata)*100))","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:42:28.620096Z","iopub.execute_input":"2023-11-01T17:42:28.620929Z","iopub.status.idle":"2023-11-01T17:42:28.630098Z","shell.execute_reply.started":"2023-11-01T17:42:28.620879Z","shell.execute_reply":"2023-11-01T17:42:28.62893Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"full_metadata.isna().sum()","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:42:28.631737Z","iopub.execute_input":"2023-11-01T17:42:28.632156Z","iopub.status.idle":"2023-11-01T17:42:28.646505Z","shell.execute_reply.started":"2023-11-01T17:42:28.632124Z","shell.execute_reply":"2023-11-01T17:42:28.645255Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"As we saw in the correlation matrix, UPDRSIII_Off strongly correlates with UPDRSIII_On. It is also slightly correlated with years_since_dx, age, and sex. So, filling missing values of UPDRSIII_Off and UPDRSIII_On using an imputation scheme seems to be reasonable. For this porpose, we employ the MICE (Multivariate Imputation by Chained Equations) algorithm that considers relationships between variables.","metadata":{}},{"cell_type":"code","source":"# Imputing using MICE\nfrom sklearn.experimental import enable_iterative_imputer\nfrom sklearn.impute import IterativeImputer\nfrom sklearn import linear_model\n\nfull_metadata_temp= full_metadata.loc[:,['Id','UPDRSIII_Off',\"UPDRSIII_On\",\"years_since_dx\",\"age\",\"sex\"]].copy()\n\ncolumns_to_update=['UPDRSIII_Off','UPDRSIII_On']\ndf_mice = full_metadata_temp.filter(columns_to_update, axis=1).copy()\n\n# Define MICE imputer and fill missing values\nmice_imputer = IterativeImputer(estimator=linear_model.BayesianRidge(), n_nearest_features=None,\n                                imputation_order='ascending')\n\ndf_mice_imputed = pd.DataFrame(mice_imputer.fit_transform(df_mice), columns=df_mice.columns)\n# Update the columns in the original DataFrame with the imputed values\nfull_metadata_temp.update(df_mice_imputed[columns_to_update])","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:43:54.486394Z","iopub.execute_input":"2023-11-01T17:43:54.488384Z","iopub.status.idle":"2023-11-01T17:43:54.829657Z","shell.execute_reply.started":"2023-11-01T17:43:54.488328Z","shell.execute_reply":"2023-11-01T17:43:54.828285Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tdcsfog_metadata_subjects.copy()\ntemp=tdcsfog_metadata_subjects.drop([\"UPDRSIII_Off\",\"UPDRSIII_On\"], axis=1)\n\nmerged_df = temp.merge(full_metadata_temp, on='Id', how='left')\n\n# Fill the null values in column 'c1' of df1 with the values from merged_df\ntdcsfog_metadata_subjects['UPDRSIII_Off'].fillna(merged_df['UPDRSIII_Off'], inplace=True)\ntdcsfog_metadata_subjects['UPDRSIII_On'].fillna(merged_df['UPDRSIII_On'], inplace=True)","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:43:56.483911Z","iopub.execute_input":"2023-11-01T17:43:56.484402Z","iopub.status.idle":"2023-11-01T17:43:56.504348Z","shell.execute_reply.started":"2023-11-01T17:43:56.484365Z","shell.execute_reply":"2023-11-01T17:43:56.503211Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tdcsfog_metadata_subjects.isna().sum()","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:43:59.275047Z","iopub.execute_input":"2023-11-01T17:43:59.275531Z","iopub.status.idle":"2023-11-01T17:43:59.288856Z","shell.execute_reply.started":"2023-11-01T17:43:59.275498Z","shell.execute_reply":"2023-11-01T17:43:59.287183Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"defog_metadata_subjects.isna().sum()","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:44:02.102728Z","iopub.execute_input":"2023-11-01T17:44:02.103258Z","iopub.status.idle":"2023-11-01T17:44:02.115621Z","shell.execute_reply.started":"2023-11-01T17:44:02.103222Z","shell.execute_reply":"2023-11-01T17:44:02.114138Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Converting Categorical Features","metadata":{}},{"cell_type":"code","source":"full_metadata.dtypes","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:44:05.284229Z","iopub.execute_input":"2023-11-01T17:44:05.284762Z","iopub.status.idle":"2023-11-01T17:44:05.297307Z","shell.execute_reply.started":"2023-11-01T17:44:05.284725Z","shell.execute_reply":"2023-11-01T17:44:05.295337Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"defog_metadata_subjects[\"sex\"] = defog_metadata_subjects[\"sex\"].map({'F' :0, 'M' :1})\ntdcsfog_metadata_subjects[\"sex\"]= tdcsfog_metadata_subjects[\"sex\"].map({'F' :0, 'M' :1})\n\ndefog_metadata_subjects[\"medication\"] = defog_metadata_subjects[\"medication\"].map({'on' :0, 'off' :1})\ntdcsfog_metadata_subjects[\"medication\"] = tdcsfog_metadata_subjects[\"medication\"].map({'on' :0, 'off' :1})","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:44:09.185179Z","iopub.execute_input":"2023-11-01T17:44:09.185735Z","iopub.status.idle":"2023-11-01T17:44:09.203159Z","shell.execute_reply.started":"2023-11-01T17:44:09.185695Z","shell.execute_reply":"2023-11-01T17:44:09.201331Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Since real values of 'subject' and 'Id' are needed in the next part, they will be converted later.","metadata":{}},{"cell_type":"markdown","source":"## Normalizing Data","metadata":{}},{"cell_type":"markdown","source":"The acceleration data needs to be normalized. The normalization takes place in the model method for the purpose of achieving a better performance.","metadata":{}},{"cell_type":"code","source":"def normalize_columns(df, columns):\n    min_values = df[columns].min()\n    max_values = df[columns].max()\n\n    normalized_df = (df[columns] - min_values) / (max_values - min_values)\n    return normalized_df","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:45:00.286292Z","iopub.execute_input":"2023-11-01T17:45:00.286876Z","iopub.status.idle":"2023-11-01T17:45:00.294588Z","shell.execute_reply.started":"2023-11-01T17:45:00.286832Z","shell.execute_reply":"2023-11-01T17:45:00.293483Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Outliers","metadata":{}},{"cell_type":"code","source":"events_df['duration'] = events_df['Completion'] - events_df['Init']","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:45:27.311233Z","iopub.execute_input":"2023-11-01T17:45:27.311816Z","iopub.status.idle":"2023-11-01T17:45:27.320322Z","shell.execute_reply.started":"2023-11-01T17:45:27.311771Z","shell.execute_reply":"2023-11-01T17:45:27.31918Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.style.use('default')\n\nevents_arr = events_df['Type'].unique()\n# Remove NaN values\nseries = pd.Series(events_arr)\nseries_without_nan = series.dropna()\nevents_arr = series_without_nan.to_numpy()\n\nplt.figure(figsize=(6, 6))\nbox_plot=plt.boxplot([events_df[events_df['Type'] == t]['duration'] for t in events_arr],\n            labels=events_arr)\nplt.xlabel('Type')\nplt.ylabel('duration')\nplt.title('Box Plot of Event Durations by Event Type', fontsize=9, pad=10)\n\n# Annotate the minimum and maximum values for each box plot\nfor i, box in enumerate(box_plot['boxes']):\n\n    max_val = box_plot['whiskers'][i*2 + 1].get_ydata()[1]\n    \n    plt.annotate(f\"Max: {max_val:.0f}\", (i+1, max_val), xytext=(10+25, +5), textcoords='offset points', ha='center')\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:45:42.042991Z","iopub.execute_input":"2023-11-01T17:45:42.04391Z","iopub.status.idle":"2023-11-01T17:45:42.372175Z","shell.execute_reply.started":"2023-11-01T17:45:42.043867Z","shell.execute_reply":"2023-11-01T17:45:42.37079Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#  delete outliers\n\n# Get the maximum value for each type from the box plot\nmax_values = {t: item.get_ydata()[1] for t, item in zip(events_df['Type'].unique(), box_plot['whiskers'][1::2])}\n\n# Drop rows with durations greater than the maximum value for each type\nevents_filtered = events_df.groupby('Type').apply(lambda x: x[x['duration'] >= (max_values[x['Type'].unique()[0]])+200]).reset_index(drop=True)","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:45:57.494652Z","iopub.execute_input":"2023-11-01T17:45:57.495124Z","iopub.status.idle":"2023-11-01T17:45:57.513676Z","shell.execute_reply.started":"2023-11-01T17:45:57.495089Z","shell.execute_reply":"2023-11-01T17:45:57.512272Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Feature Engineering","metadata":{}},{"cell_type":"code","source":"def reader(file, module, pre_type=None):\n    if module==\"tdcsfog\":\n        window_length =4048\n    elif module==\"defog\":\n        window_length=4048\n    try:\n\n        df = pd.read_csv(file)\n\n        path_split = file.split('/')\n        Id = path_split[-1].split('.')[0]\n        df['Id'] = Id\n        \n        if module==\"defog\":\n            data= df.merge(defog_metadata_subjects,how=\"left\",on=\"Id\")\n            if 'Valid' in data.columns and 'Task' in data.columns and pre_type==\"train\":\n                data = data.loc[(data['Valid'] == True) & (data[\"Task\"] == True)]\n                data.drop([\"Valid\", \"Task\"], axis=1, inplace=True)\n            elif 'Valid' in data.columns and 'Task' in data.columns:\n                data.drop([\"Valid\", \"Task\"], axis=1, inplace=True)\n\n        elif module == \"tdcsfog\":\n            data= df.merge(tdcsfog_metadata_subjects,how=\"left\",on=\"Id\")\n\n        data[\"acc_sum\"]= data[\"AccV\"]+data[\"AccML\"]+data[\"AccAP\"]\n        data['time_frac']=(data[\"Time\"]/data[\"Time\"].max()).values\n        acc_columns=[\"AccV\",\"AccML\",\"AccAP\"]\n        \n        columns_to_normalize = ['AccV', 'AccML', 'AccAP']\n        data[columns_to_normalize] = normalize_columns(data, columns_to_normalize)   \n        \n        for acc in acc_columns:\n            data[f'{acc}_cumsum'] = data[acc].cumsum()\n            data[f'{acc}_rolling_sum'] = data[acc].rolling(window=window_length, min_periods=1).sum()\n            data[f'{acc}_rolling_min'] = data[acc].rolling(window=window_length, min_periods=1).min()\n            data[f'{acc}_rolling_max'] = data[acc].rolling(window=window_length, min_periods=1).max()\n            data[f'{acc}_rolling_mean'] = data[acc].rolling(window=window_length, min_periods=1).mean()\n            data[f'{acc}_rolling_std'] = data[acc].rolling(window=window_length, min_periods=1).std()\n            data[f'{acc}_rolling_delta'] = data[f'{acc}_rolling_max'] - data[f'{acc}_rolling_min']        \n            data[f'{acc}_EWMA_02'] = data[acc].ewm(alpha=0.2).mean()\n        \n        for c in acc_columns:\n            data[f\"{c}_lead_diff\"] = data[c].diff(-1)\n            data[f\"{c}_lag_diff\"] = data[c].diff()\n\n\n        data.fillna(method='backfill', inplace=True)\n        \n#         for train data \n        events_id = events_filtered[events_filtered[\"Id\"] == Id]\n\n        events_rows = pd.DataFrame()\n        if len(events_id)>0:\n            return None\n                \n        return data\n    except: pass","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:46:32.961793Z","iopub.execute_input":"2023-11-01T17:46:32.962296Z","iopub.status.idle":"2023-11-01T17:46:32.985188Z","shell.execute_reply.started":"2023-11-01T17:46:32.96226Z","shell.execute_reply":"2023-11-01T17:46:32.983647Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_defog_df = pd.concat([reader(f,\"defog\",\"train\") for f in tqdm(train_defog)]).fillna(-1); print(train_defog_df.shape)","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:46:44.634937Z","iopub.execute_input":"2023-11-01T17:46:44.635408Z","iopub.status.idle":"2023-11-01T17:47:31.466235Z","shell.execute_reply.started":"2023-11-01T17:46:44.635372Z","shell.execute_reply":"2023-11-01T17:47:31.46456Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_defog_df =reduce_memory_usage(train_defog_df)","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:48:05.047084Z","iopub.execute_input":"2023-11-01T17:48:05.047541Z","iopub.status.idle":"2023-11-01T17:48:05.628936Z","shell.execute_reply.started":"2023-11-01T17:48:05.04751Z","shell.execute_reply":"2023-11-01T17:48:05.626667Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_tdcsfog_df = pd.concat([reader(f,\"tdcsfog\") for f in tqdm(train_tdcsfog)]).fillna(0); print(train_tdcsfog_df.shape)","metadata":{"execution":{"iopub.status.busy":"2023-11-01T18:06:38.764073Z","iopub.execute_input":"2023-11-01T18:06:38.764608Z","iopub.status.idle":"2023-11-01T18:07:45.573517Z","shell.execute_reply.started":"2023-11-01T18:06:38.764561Z","shell.execute_reply":"2023-11-01T18:07:45.57211Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Model\n","metadata":{}},{"cell_type":"markdown","source":"### Model Selection\nFor this project, after tuning different ML algorithms, LightGBM algorithm is taken into account for the following reasons.\n\nThe dataset is large including many features, so a highly-effiecient model is required.\nThe task involves multi-class classification.\nThe multi-class problem exhibits imbalanced classes.\nIt is crucial to capture complex and non-linear relationships in the data.","metadata":{}},{"cell_type":"markdown","source":"## Model Training","metadata":{}},{"cell_type":"code","source":"param_grid = {\n  'max_depth': [6,8,10],\n  'learning_rate': [0.15,0.1,0.01],\n  'n_estimators': [50,70,90]\n} ","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:48:00.158804Z","iopub.execute_input":"2023-11-01T17:48:00.159267Z","iopub.status.idle":"2023-11-01T17:48:00.166446Z","shell.execute_reply.started":"2023-11-01T17:48:00.159234Z","shell.execute_reply":"2023-11-01T17:48:00.165178Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"targets = [\"StartHesitation\", \"Turn\", 'Walking']","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:48:29.011995Z","iopub.execute_input":"2023-11-01T17:48:29.012425Z","iopub.status.idle":"2023-11-01T17:48:29.018819Z","shell.execute_reply.started":"2023-11-01T17:48:29.012393Z","shell.execute_reply":"2023-11-01T17:48:29.017451Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def model(df, module):\n    \n    df = df.apply(factorize_column)\n\n    y_train = df.loc[:, targets]\n\n    if module == \"defog\":\n        X_train = df.drop(targets, axis=1)\n\n    elif module == \"tdcsfog\":\n        X_train = df.drop([\"StartHesitation\", \"Turn\", 'Walking', 'UPDRSIII_On', 'UPDRSIII_Off'], axis=1)\n      \n    models = []\n    aps=[]\n\n    # Get Ids from X_train\n    Ids = X_train['Id']\n\n    # Create the GroupKFold object based on 'Id' column\n    group_cv = GroupKFold(n_splits=5)\n    \n    for label in targets:\n        y_train_l = y_train[label]\n\n        # LightGBM classifier\n        lgbm = lgb.LGBMClassifier(objective=\"binary\", scale_pos_weight=np.sqrt(y_train_l.value_counts()[0] / y_train_l.value_counts()[1]),\n                                  max_depth=8, learning_rate=0.1, n_estimators=70)\n        \n        aps_l = []\n        # Perform group-based cross-validation\n        for train_idx, val_idx in group_cv.split(X_train, y_train_l, groups=Ids):\n            X_train_fold, X_val_fold = X_train.iloc[train_idx], X_train.iloc[val_idx]\n            y_train_fold, y_val_fold = y_train_l.iloc[train_idx], y_train_l.iloc[val_idx]\n\n            # Fit the model on the training fold\n            lgbm.fit(X_train_fold, y_train_fold)\n\n            # Calculate average precision for the validation fold\n            ap_val = average_precision_score(y_val_fold, lgbm.predict_proba(X_val_fold)[:, 1])\n            aps_l.append(ap_val)\n        print(\"Average precision of {} associated with all folds: {:.4f}\".format(label, np.mean(aps_l)))\n        aps.append(aps_l)    \n    print(\"Overall precision of all folds: {:.4f}\".format( np.mean(aps)))\n#     main model trained on entired data\n    for label in targets:\n        y_train_l = y_train[label]\n\n        # LightGBM classifier\n        lgbm = lgb.LGBMClassifier(objective=\"binary\", scale_pos_weight=np.sqrt(y_train_l.value_counts()[0] / y_train_l.value_counts()[1]),\n                              max_depth=8, learning_rate=0.1, n_estimators=70)\n        lgbm.fit(X_train, y_train_l)\n        models.append(lgbm)\n    return models","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:48:45.477426Z","iopub.execute_input":"2023-11-01T17:48:45.479095Z","iopub.status.idle":"2023-11-01T17:48:45.494849Z","shell.execute_reply.started":"2023-11-01T17:48:45.478978Z","shell.execute_reply":"2023-11-01T17:48:45.493425Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Model Evaluation","metadata":{}},{"cell_type":"code","source":"defog_models=model(train_defog_df,\"defog\")","metadata":{"execution":{"iopub.status.busy":"2023-11-01T17:50:42.882754Z","iopub.execute_input":"2023-11-01T17:50:42.883314Z","iopub.status.idle":"2023-11-01T18:03:39.945595Z","shell.execute_reply.started":"2023-11-01T17:50:42.883275Z","shell.execute_reply":"2023-11-01T18:03:39.943521Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# tdcsfog model\ntdcsfog_models=model(train_tdcsfog_df,\"tdcsfog\")","metadata":{"execution":{"iopub.status.busy":"2023-11-01T18:30:15.947538Z","iopub.execute_input":"2023-11-01T18:30:15.948119Z","iopub.status.idle":"2023-11-01T18:52:08.193278Z","shell.execute_reply.started":"2023-11-01T18:30:15.948079Z","shell.execute_reply":"2023-11-01T18:52:08.191018Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Prediction","metadata":{}},{"cell_type":"code","source":"def predict(models, test_df, module):\n    X_test = test_df.apply(factorize_column)\n\n    if module == \"tdcsfog\":\n        X_test= X_test.drop(['UPDRSIII_On', 'UPDRSIII_Off'], axis=1)\n    \n    y_predict = pd.DataFrame()\n    \n    \n    for index, label in enumerate(targets):\n         y_predict[label] = models[index].predict_proba(X_test)[:, 1]\n            \n    test_df[\"Time\"] = test_df[\"Time\"].astype(str)\n    test_df=test_df.reset_index(drop=True)\n    y_predict.insert(0, 'Id', test_df[\"Id\"] + \"_\" + test_df[\"Time\"])\n    return y_predict","metadata":{"execution":{"iopub.status.busy":"2023-11-01T18:56:10.215938Z","iopub.execute_input":"2023-11-01T18:56:10.216511Z","iopub.status.idle":"2023-11-01T18:56:10.234028Z","shell.execute_reply.started":"2023-11-01T18:56:10.216473Z","shell.execute_reply":"2023-11-01T18:56:10.23187Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_defog_df = pd.concat([reader(f,\"defog\") for f in tqdm(test_defog)]).fillna(-1); print(test_defog_df.shape)\ntest_tdcsfog_df = pd.concat([reader(f,\"tdcsfog\") for f in tqdm(test_tdcsfog)]).fillna(-1); print(test_tdcsfog_df.shape)\n\n# predict defog test df\ny_defog_predict = predict(defog_models, test_defog_df,\"defog\")\n# predict tdcsfog test df\ny_tdcsfog_predict = predict(tdcsfog_models,test_tdcsfog_df, \"tdcsfog\")","metadata":{"execution":{"iopub.status.busy":"2023-11-01T18:56:14.787773Z","iopub.execute_input":"2023-11-01T18:56:14.789088Z","iopub.status.idle":"2023-11-01T18:56:19.097512Z","shell.execute_reply.started":"2023-11-01T18:56:14.789043Z","shell.execute_reply":"2023-11-01T18:56:19.096592Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"final_result=pd.concat([y_tdcsfog_predict, y_defog_predict])\nfinal_result[\"StartHesitation\"]=np.round(final_result[\"StartHesitation\"].clip(0.0,1.0),8)\nfinal_result[\"Turn\"]=np.round(final_result[\"Turn\"].clip(0.0,1.0),8)\nfinal_result[\"Walking\"]=np.round(final_result[\"Walking\"].clip(0.0,1.0),8)\nfinal_result.to_csv('submission.csv', index=False)\nfinal_result.head(","metadata":{"execution":{"iopub.status.busy":"2023-11-01T18:58:51.659146Z","iopub.execute_input":"2023-11-01T18:58:51.665711Z","iopub.status.idle":"2023-11-01T18:58:53.554026Z","shell.execute_reply.started":"2023-11-01T18:58:51.665661Z","shell.execute_reply":"2023-11-01T18:58:53.55244Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}