{"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":"markdown","source":"# time-series 🤝 tsflex 🚀","metadata":{}},{"cell_type":"markdown","source":"### **Thanks to great works from JEROENVDD and DATAMANYO.**\n\n### new improvements based on groupkfold-cross-validation-tsflex\n\n1. use LGBM model with early stop\n2. memory optimization by dumpping middle fold train data on disk\n\n### past improvements \n\n1. add metadata infomation and subject infomation, fix a little bug of subject feature in JEROENVDD‘s origin notebook\n2. make GroupKfold Cross Validation\n\n#### reference\n\n* @JEROENVDD\n    * https://www.kaggle.com/code/jeroenvdd/time-series-tsflex\n* @DATAMANYO\n    * https://www.kaggle.com/code/kimtaehun/simple-lgbm-multi-class-classification-baseline\n* @此般浅薄\n    * https://www.kaggle.com/code/xzj19013742/groupkfold-cross-validation-tsflex\n\n<br>","metadata":{}},{"cell_type":"markdown","source":"<div style=\"background-color:#f2f2f2; padding:20px; border-radius: 10px;\">\n    <h2 style=\"color:#595959;\">Check out <a href=\"https://github.com/predict-idlab/tsflex\" target=\"_blank\" style=\"color:#0099cc;\">tsflex</a>!</h2>\n    <h4 style=\"color:#737373;\">tsflex is a Python package for flexible and efficient time series feature extraction. It's great for data preprocessing and feature engineering for time series data. Check it out on <a href=\"https://github.com/predict-idlab/tsflex\" target=\"_blank\" style=\"color:#0099cc;\">GitHub</a> today!</h4>\n    \n<p style=\"color:#737373;\">This notebook is a fork of the <a href=\"https://www.kaggle.com/code/jazivxt/familiar-solvs\" target=\"_blank\" style=\"color:#0099cc;\">familiar-solvs notebook of jazivxt</a> and adds tsflex to extract some basic <a href=\"https://github.com/dmbee/seglearn\" target=\"_blank\" style=\"color:#0099cc;\">seglearn</a> features.</p>\n    \n</div>","metadata":{}},{"cell_type":"code","source":"# Install tsflex and seglearn\n!pip install tsflex --no-index --find-links=file:///kaggle/input/time-series-tools\n!pip install seglearn --no-index --find-links=file:///kaggle/input/time-series-tools","metadata":{"execution":{"iopub.status.busy":"2023-03-27T02:26:00.583448Z","iopub.execute_input":"2023-03-27T02:26:00.583927Z","iopub.status.idle":"2023-03-27T02:26:28.255810Z","shell.execute_reply.started":"2023-03-27T02:26:00.583881Z","shell.execute_reply":"2023-03-27T02:26:28.254033Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nfrom tqdm.auto import tqdm\nfrom sklearn import *\nimport glob\n\np = '/kaggle/input/tlvmc-parkinsons-freezing-gait-prediction/'\n\ntrain = glob.glob(p+'train/**/**')\ntest = glob.glob(p+'test/**/**')\nsubjects = pd.read_csv(p+'subjects.csv')\ntasks = pd.read_csv(p+'tasks.csv')\nsub = pd.read_csv(p+'sample_submission.csv')\n\ntdcsfog_metadata=pd.read_csv('/kaggle/input/tlvmc-parkinsons-freezing-gait-prediction/tdcsfog_metadata.csv')\ndefog_metadata=pd.read_csv('/kaggle/input/tlvmc-parkinsons-freezing-gait-prediction/defog_metadata.csv')\n# daily_metadata=pd.read_csv('/kaggle/input/tlvmc-parkinsons-freezing-gait-prediction/daily_metadata.csv')\ntdcsfog_metadata['Module']='tdcsfog'\ndefog_metadata['Module']='defog'\n# daily_metadata['Module']='daily'\nmetadata=pd.concat([tdcsfog_metadata,defog_metadata])\nmetadata","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-03-27T02:26:28.259209Z","iopub.execute_input":"2023-03-27T02:26:28.259781Z","iopub.status.idle":"2023-03-27T02:26:30.394522Z","shell.execute_reply.started":"2023-03-27T02:26:28.259715Z","shell.execute_reply":"2023-03-27T02:26:30.393090Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# https://www.kaggle.com/code/jazivxt/familiar-solvs\ntasks['Duration'] = tasks['End'] - tasks['Begin']\ntasks = pd.pivot_table(tasks, values=['Duration'], index=['Id'], columns=['Task'], aggfunc='sum', fill_value=0)\ntasks.columns = [c[-1] for c in tasks.columns]\ntasks = tasks.reset_index()\ntasks['t_kmeans'] = cluster.KMeans(n_clusters=10, random_state=3).fit_predict(tasks[tasks.columns[1:]])\n\nsubjects = subjects.fillna(0).groupby('Subject').median()\nsubjects = subjects.reset_index()\n# subjects.rename(columns={'Subject':'Id'}, inplace=True)\nsubjects['s_kmeans'] = cluster.KMeans(n_clusters=10, random_state=3).fit_predict(subjects[subjects.columns[1:]])\nsubjects=subjects.rename(columns={'Visit':'s_Visit','Age':'s_Age','YearsSinceDx':'s_YearsSinceDx','UPDRSIII_On':'s_UPDRSIII_On','UPDRSIII_Off':'s_UPDRSIII_Off','NFOGQ':'s_NFOGQ'})\n\ndisplay(tasks)\ndisplay(subjects)","metadata":{"execution":{"iopub.status.busy":"2023-03-27T02:26:30.396248Z","iopub.execute_input":"2023-03-27T02:26:30.396703Z","iopub.status.idle":"2023-03-27T02:26:30.681043Z","shell.execute_reply.started":"2023-03-27T02:26:30.396643Z","shell.execute_reply":"2023-03-27T02:26:30.679129Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## merge metadata and subject info","metadata":{}},{"cell_type":"code","source":"import pathlib\n\n\ncomplex_featlist=['Visit','Test','Medication','s_Visit','s_Age','s_YearsSinceDx','s_UPDRSIII_On','s_UPDRSIII_Off','s_NFOGQ','s_kmeans']\nmetadata_complex=metadata.merge(subjects,how='left',on='Subject').copy()\nmetadata_complex['Medication']=metadata_complex['Medication'].factorize()[0]\ntrain_ids=[pathlib.Path(i).parts[-1].split('.')[0] for i in glob.glob(p+'train/**/**')]\nmetadata_complex['is_train']=metadata_complex['Id'].isin(train_ids)\n\ndisplay(metadata_complex)","metadata":{"execution":{"iopub.status.busy":"2023-03-27T02:26:30.685273Z","iopub.execute_input":"2023-03-27T02:26:30.685855Z","iopub.status.idle":"2023-03-27T02:26:30.738945Z","shell.execute_reply.started":"2023-03-27T02:26:30.685791Z","shell.execute_reply":"2023-03-27T02:26:30.737680Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"execution":{"iopub.status.busy":"2023-03-27T02:26:30.740319Z","iopub.execute_input":"2023-03-27T02:26:30.740907Z","iopub.status.idle":"2023-03-27T02:26:30.770720Z","shell.execute_reply.started":"2023-03-27T02:26:30.740849Z","shell.execute_reply":"2023-03-27T02:26:30.769228Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Create a tsflex feature collection","metadata":{}},{"cell_type":"code","source":"from seglearn.feature_functions import base_features, emg_features\n\nfrom tsflex.features import FeatureCollection, MultipleFeatureDescriptors\nfrom tsflex.features.integrations import seglearn_feature_dict_wrapper\n\n\nbasic_feats = MultipleFeatureDescriptors(\n    functions=seglearn_feature_dict_wrapper(base_features()),\n    series_names=['AccV', 'AccML', 'AccAP'],\n    windows=[5_000],\n    strides=[5_000],\n)\n\nemg_feats = emg_features()\ndel emg_feats['simple square integral'] # is same as abs_energy (which is in base_features)\n\nemg_feats = MultipleFeatureDescriptors(\n    functions=seglearn_feature_dict_wrapper(emg_feats),\n    series_names=['AccV', 'AccML', 'AccAP'],\n    windows=[5_000],\n    strides=[5_000],\n)\n\nfc = FeatureCollection([basic_feats, emg_feats])","metadata":{"execution":{"iopub.status.busy":"2023-03-27T02:26:30.772174Z","iopub.execute_input":"2023-03-27T02:26:30.772933Z","iopub.status.idle":"2023-03-27T02:26:30.837343Z","shell.execute_reply.started":"2023-03-27T02:26:30.772889Z","shell.execute_reply":"2023-03-27T02:26:30.835772Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Extract the features for 5 train fold","metadata":{}},{"cell_type":"code","source":"import pathlib\ndef reader(f):\n    try:\n        df = pd.read_csv(f, index_col=\"Time\", usecols=['Time', 'AccV', 'AccML', 'AccAP', 'StartHesitation', 'Turn' , 'Walking'])\n        df['Id'] = f.split('/')[-1].split('.')[0]\n        df['Module'] = pathlib.Path(f).parts[-2]\n        df = pd.merge(df, tasks[['Id','t_kmeans']], how='left', on='Id').fillna(-1)\n#         df = pd.merge(df, subjects[['Id','s_kmeans']], how='left', on='Id').fillna(-1)\n        df = pd.merge(df, metadata_complex[['Id','Subject']+['Visit','Test','Medication','s_kmeans']], how='left', on='Id').fillna(-1)\n        df_feats = fc.calculate(df, return_df=True, include_final_window=True, approve_sparsity=True, window_idx=\"begin\").astype(np.float32)\n        df = df.merge(df_feats, how=\"left\", left_index=True, right_index=True)\n        df.fillna(method=\"ffill\", inplace=True)\n        return df\n    except: pass\n# train = pd.concat([reader(f) for f in tqdm(train)]).fillna(0); print(train.shape)\n# cols = [c for c in train.columns if c not in ['Id','Subject','Module', 'Time', 'StartHesitation', 'Turn' , 'Walking', 'Valid', 'Task','Event']]\n# pcols = ['StartHesitation', 'Turn' , 'Walking']\n# scols = ['Id', 'StartHesitation', 'Turn' , 'Walking']","metadata":{"execution":{"iopub.status.busy":"2023-03-27T02:26:30.839176Z","iopub.execute_input":"2023-03-27T02:26:30.839772Z","iopub.status.idle":"2023-03-27T02:26:30.851320Z","shell.execute_reply.started":"2023-03-27T02:26:30.839731Z","shell.execute_reply":"2023-03-27T02:26:30.849888Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import GroupKFold\nN_FOLDS=5\nn_use_fold=5\nchoices = [1, 2, 3]\n\ntrain_metadata_complex=metadata_complex[metadata_complex['is_train']==True].reset_index(drop=True)\n\n\nkfold = GroupKFold(N_FOLDS)\ngroups=kfold.split(train_metadata_complex, groups=train_metadata_complex.Subject)\ngroups=list(groups)\n\n#### get Id of each fold\nfold_idss=[train_metadata_complex.loc[i[1],['Module','Id']].drop_duplicates().apply(\n        lambda x:f\"/kaggle/input/tlvmc-parkinsons-freezing-gait-prediction/train/{x['Module']}/{x['Id']}.csv\",axis=1\n    ).tolist()\n           for i in groups]\n","metadata":{"execution":{"iopub.status.busy":"2023-03-27T02:26:30.853404Z","iopub.execute_input":"2023-03-27T02:26:30.854137Z","iopub.status.idle":"2023-03-27T02:26:30.908213Z","shell.execute_reply.started":"2023-03-27T02:26:30.854066Z","shell.execute_reply":"2023-03-27T02:26:30.906791Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for fold,fold_ids in enumerate(fold_idss):\n    fold_train=pd.concat([reader(f) for f in tqdm(fold_ids)]).fillna(0); print(fold_train.shape)\n    fold_train['fold']=fold\n    conditions = [\n        (fold_train['StartHesitation'] == 1),\n        (fold_train['Turn'] == 1),\n        (fold_train['Walking'] == 1)]\n\n    fold_train['event'] = np.select(conditions, choices, default=0)\n    fold_train.to_parquet('fold_train.pq',partition_cols=['fold'])\n\ncols = [c for c in fold_train.columns if c not in ['Id','Subject','Module', 'Time', 'StartHesitation', 'Turn' , 'Walking', 'Valid', 'Task','Event','event','fold']]\npcols = ['StartHesitation', 'Turn' , 'Walking']\nscols = ['Id', 'StartHesitation', 'Turn' , 'Walking']","metadata":{"execution":{"iopub.status.busy":"2023-03-27T02:26:30.909737Z","iopub.execute_input":"2023-03-27T02:26:30.910118Z","iopub.status.idle":"2023-03-27T02:33:45.527363Z","shell.execute_reply.started":"2023-03-27T02:26:30.910077Z","shell.execute_reply":"2023-03-27T02:33:45.525817Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Train the model","metadata":{}},{"cell_type":"code","source":"import warnings\nimport lightgbm as lgb\nwarnings.filterwarnings('ignore')\n\n\n\n#setting up the parameters\nparams={}\nparams['learning_rate']=0.03\nparams['boosting_type']='gbdt' #GradientBoostingDecisionTree\nparams['objective']='multiclass' #Multi-class target feature\nparams['metric']='multi_logloss' #metric for multi-class\nparams['max_depth']=7\nparams['num_class']=4 #no.of unique values in the target class not inclusive of the end value\nparams['verbose']=-1\n\n\nregs=[]\ncvs=[]\n\nfor fold in tqdm(range(N_FOLDS), total=N_FOLDS, desc=\"Folds\"):\n    if fold>=n_use_fold:\n        break\n    train_filter=[[('fold','=',fld)] for fld in range(N_FOLDS) if fld !=fold]\n    train=pd.read_parquet('fold_train.pq',filters=train_filter).sample(n=2000000,random_state=100).reset_index(drop=True)\n    valid=pd.read_parquet('fold_train.pq',filters=[('fold','=',fold)])\n    x_tr,y_tr,e_tr=train[cols],train[pcols],train['event']\n    x_te,y_te,e_te=valid[cols],valid[pcols],valid['event']    \n    \n    lgb_train = lgb.Dataset(x_tr, e_tr)\n    lgb_valid = lgb.Dataset(x_te, e_te)\n    \n    #training the model\n    reg = lgb.train(\n        params = params,\n        train_set = lgb_train,\n        num_boost_round = 10500,\n        valid_sets = [lgb_train, lgb_valid],\n        early_stopping_rounds = 50,\n        verbose_eval = 500,\n        )\n    \n    \n    regs.append(reg)\n    cv=metrics.average_precision_score(y_te, reg.predict(x_te)[:,1:].clip(0.0,1.0))\n    cvs.append(cv)\n\ndisplay(pd.Series(cvs).to_frame().T)\n# print(cvs)\nprint(sum(cvs)/n_use_fold)","metadata":{"execution":{"iopub.status.busy":"2023-03-27T02:33:45.531238Z","iopub.execute_input":"2023-03-27T02:33:45.531632Z","iopub.status.idle":"2023-03-27T03:01:34.712644Z","shell.execute_reply.started":"2023-03-27T02:33:45.531592Z","shell.execute_reply":"2023-03-27T03:01:34.710768Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"valid_thre=0\nvalid_modelids=[ind for ind,cv in enumerate(cvs) if cv>valid_thre]\nvalid_modelids","metadata":{"execution":{"iopub.status.busy":"2023-03-27T03:01:34.715459Z","iopub.execute_input":"2023-03-27T03:01:34.716161Z","iopub.status.idle":"2023-03-27T03:01:34.726528Z","shell.execute_reply.started":"2023-03-27T03:01:34.716115Z","shell.execute_reply":"2023-03-27T03:01:34.725054Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Predict for test","metadata":{}},{"cell_type":"code","source":"sub['t'] = 0\nsubmission = []\nfor f in test:\n    df = pd.read_csv(f)\n    df.set_index('Time', drop=True, inplace=True)\n    df['Id'] = f.split('/')[-1].split('.')[0]\n#     df = df.fillna(0).reset_index(drop=True)\n    df = pd.merge(df, tasks[['Id','t_kmeans']], how='left', on='Id').fillna(-1)\n    df = pd.merge(df, metadata_complex[['Id','Subject']+['Visit','Test','Medication','s_kmeans']], how='left', on='Id').fillna(-1)\n    df_feats = fc.calculate(df, return_df=True, include_final_window=True, approve_sparsity=True, window_idx=\"begin\")\n    df = df.merge(df_feats, how=\"left\", left_index=True, right_index=True)\n    df.fillna(method=\"ffill\", inplace=True)\n    \n    res_vals=[]\n    for i_fold in range(n_use_fold):\n        if i_fold in valid_modelids:\n            res_val=np.round(regs[i_fold].predict(df[cols])[:,1:].clip(0.0,1.0),5)\n            res_vals.append(np.expand_dims(res_val,axis=2))\n    res_vals=np.mean(np.concatenate(res_vals,axis=2),axis=2)\n    res = pd.DataFrame(res_vals, columns=pcols)\n    \n    df = pd.concat([df,res], axis=1)\n    df['Id'] = df['Id'].astype(str) + '_' + df.index.astype(str)\n    submission.append(df[scols])\nsubmission = pd.concat(submission)\nsubmission = pd.merge(sub[['Id','t']], submission, how='left', on='Id').fillna(0.0)\nsubmission[scols].to_csv('submission.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2023-03-27T03:01:34.728287Z","iopub.execute_input":"2023-03-27T03:01:34.728650Z","iopub.status.idle":"2023-03-27T03:01:46.649586Z","shell.execute_reply.started":"2023-03-27T03:01:34.728615Z","shell.execute_reply":"2023-03-27T03:01:46.648196Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}