{"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":"### XGBoost Train and Test online","metadata":{}},{"cell_type":"code","source":"import os\nimport gc\nimport sys\n\nimport numpy as np\nimport pandas as pd\nimport polars as pl\n\ncategory = [\n    'event_name', 'name', 'fqid', 'room_fqid', 'text_fqid'\n]\n\nnumeric = [\n    'page', 'room_coor_x', 'room_coor_y', 'screen_coor_x', 'screen_coor_y',\n    'hover_duration', 'elapsed_time_diff'\n]","metadata":{"execution":{"iopub.status.busy":"2023-06-02T05:17:39.455312Z","iopub.execute_input":"2023-06-02T05:17:39.455779Z","iopub.status.idle":"2023-06-02T05:17:39.669889Z","shell.execute_reply.started":"2023-06-02T05:17:39.455690Z","shell.execute_reply":"2023-06-02T05:17:39.668890Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Feature engineering","metadata":{}},{"cell_type":"code","source":"dtypes={ \n    'elapsed_time':np.int32,\n    'event_name':'category',\n    'name':'category',\n    'level':np.uint8,\n    'page':'category',\n    'room_coor_x':np.float32,\n    'room_coor_y':np.float32,\n    'screen_coor_x':np.float32,\n    'screen_coor_y':np.float32,\n    'hover_duration':np.float32,\n     'text':'category',\n     'fqid':'category',\n     'room_fqid':'category',\n     'text_fqid':'category',\n     'fullscreen':'category',\n     'hq':'category',\n     'music':'category',\n     'level_group':'category'}\ntrain=pd.read_csv('/kaggle/input/predict-student-performance-from-game-play/train.csv', dtype=dtypes)","metadata":{"execution":{"iopub.status.busy":"2023-06-02T05:17:39.676074Z","iopub.execute_input":"2023-06-02T05:17:39.678390Z","iopub.status.idle":"2023-06-02T05:19:39.443184Z","shell.execute_reply.started":"2023-06-02T05:17:39.678348Z","shell.execute_reply":"2023-06-02T05:19:39.442282Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# group and preprocess for some column\n# calculate delta value for some column and fill none value\ndtypes={\n    'elapsed_time':pl.Int32,\n    'level':pl.Int8,\n    'page':pl.Float32,\n    'room_coor_x':pl.Float32,\n    'room_coor_y':pl.Float32,\n    'screen_coor_x':pl.Float32,\n    'screen_coor_y':pl.Float32,\n    'hover_duration':pl.Float32,\n}\ncolumns = [\n    (\n        (pl.col('elapsed_time') - pl.col('elapsed_time').shift(1))\n        .fill_null(0)\n        .clip(0, 1e9)\n        .over(['session_id', 'level'])\n        .alias('elapsed_time_diff')\n    ),\n    (\n        (pl.col('screen_coor_x') - pl.col('screen_coor_x').shift(1))\n        .abs().\n        over(['session_id', 'level'])\n    ),\n    (\n        (pl.col(\"screen_coor_y\") - pl.col(\"screen_coor_y\").shift(1))\n        .abs()\n        .over([\"session_id\", \"level\"])\n    ),\n    (\n        (pl.col('room_coor_x') - pl.col('room_coor_x').shift(1))\n        .abs().\n        over(['session_id', 'level'])\n    ),\n    (\n        (pl.col(\"room_coor_y\") - pl.col(\"room_coor_y\").shift(1))\n        .abs()\n        .over([\"session_id\", \"level\"])\n    ),\n    pl.col(\"fqid\").fill_null(\"fqid_None\"),\n    pl.col(\"text_fqid\").fill_null(\"text_fqid_None\")\n]\n\n# train = pl.read_csv('/kaggle/input/predict-student-performance-from-game-play/train.csv', dtypes=dtypes).drop(['fullscreen', 'hq', 'music']).with_columns(columns)\n# # train = pl.read_csv('train.csv').drop(['fullscreen', 'hq', 'music']).with_columns(columns)\n\ntrain = pl.from_pandas(train).drop(['fullscreen', 'hq', 'music']).with_columns(columns)\n\nfqid_lists = list(train['fqid'].unique())\ntext_fqid_lists = list(train['text_fqid'].unique())\nroom_fqid_lists = list(train['room_fqid'].unique())\nname_feature_lists = list(train['name'].unique())\nevent_name_feature_lists = list(train['event_name'].unique())\nlevels = list(train['level'].unique())\nlevel_groups = list(train['level_group'].unique())\nprint(levels)","metadata":{"execution":{"iopub.status.busy":"2023-06-02T05:19:39.444693Z","iopub.execute_input":"2023-06-02T05:19:39.445251Z","iopub.status.idle":"2023-06-02T05:20:02.698018Z","shell.execute_reply.started":"2023-06-02T05:19:39.445218Z","shell.execute_reply":"2023-06-02T05:20:02.697092Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def elapsed_diff_agg(column, column_value_list, feature_suffix):\n    elapsed_agg = [\n        *[pl.col(column).filter(pl.col(column) == c).count().alias(f\"{c}_{column}_counts_{feature_suffix}\") for c in column_value_list], # calculate number of different fqid\n\n        *[pl.col(\"elapsed_time_diff\").filter(pl.col(column) == c).std().alias(f\"{c}_{column}_elapsed_std_{feature_suffix}\") for\n          c in column_value_list],\n        *[pl.col(\"elapsed_time_diff\").filter(pl.col(column) == c).mean().alias(f\"{c}_{column}_elapsed_mean_{feature_suffix}\") for\n          c in column_value_list],\n        *[pl.col(\"elapsed_time_diff\").filter(pl.col(column) == c).max().alias(f\"{c}_{column}_elapsed_max_{feature_suffix}\") for\n          c in column_value_list],\n        *[pl.col(\"elapsed_time_diff\").filter(pl.col(column) == c).min().alias(f\"{c}_{column}_elapsed_min_{feature_suffix}\") for\n          c in column_value_list],\n        *[pl.col(\"elapsed_time_diff\").filter(pl.col(column) == c).sum().alias(f\"{c}_{column}_elapsed_sum_{feature_suffix}\") for\n          c in column_value_list], # calculate statistics value of elapsed time delta as we discuss\n    ]\n    return elapsed_agg\n\ndef feature_engineer(x, grp, feature_suffix, use_extra=True):\n    aggs = [\n        pl.col('index').count().alias(f\"session_number_{feature_suffix}\"), # the number of events of a session\n        *[pl.col(c).drop_nulls().n_unique().alias(f\"{c}_unique_{feature_suffix}\") for c in category], # drop none and calcu number of unique value\n        *[pl.col(c).std().alias(f\"{c}_std_{feature_suffix}\") for c in numeric],\n        *[pl.col(c).mean().alias(f\"{c}_mean_{feature_suffix}\") for c in numeric],\n        *[pl.col(c).min().alias(f\"{c}_min_{feature_suffix}\") for c in numeric],\n        *[pl.col(c).max().alias(f\"{c}_max_{feature_suffix}\") for c in numeric],\n        *[pl.col(c).sum().alias(f\"{c}_sum_{feature_suffix}\") for c in numeric], # calculate statistic value of numeric values\n    ]\n    aggs.extend(elapsed_diff_agg('fqid', fqid_lists, feature_suffix))\n    aggs.extend(elapsed_diff_agg('text_fqid', text_fqid_lists, feature_suffix))\n    aggs.extend(elapsed_diff_agg('room_fqid', room_fqid_lists, feature_suffix))\n    aggs.extend(elapsed_diff_agg('name', name_feature_lists, feature_suffix))\n    aggs.extend(elapsed_diff_agg('event_name', event_name_feature_lists, feature_suffix))\n    aggs.extend(elapsed_diff_agg('level', levels, feature_suffix))\n    aggs.extend(elapsed_diff_agg('level_group', level_groups, feature_suffix))\n\n    df = x.groupby(['session_id'], maintain_order=True).agg(aggs).sort('session_id')\n    \n    if use_extra:\n        if grp == '5-12':\n            aggs = [\n                pl.col(\"elapsed_time\").filter((pl.col(\"text\")==\"Here's the log book.\")\n                                              |(pl.col(\"fqid\")=='logbook.page.bingo'))\n                    .apply(lambda s: s.max()-s.min()).alias(\"logbook_bingo_duration\"),\n                pl.col(\"index\").filter(\n                    (pl.col(\"text\") == \"Here's the log book.\") | (pl.col(\"fqid\") == 'logbook.page.bingo')).apply(\n                    lambda s: s.max() - s.min()).alias(\"logbook_bingo_indexCount\"),\n                pl.col(\"elapsed_time\").filter(\n                    ((pl.col(\"event_name\") == 'navigate_click') & (pl.col(\"fqid\") == 'reader')) | (\n                                pl.col(\"fqid\") == \"reader.paper2.bingo\")).apply(lambda s: s.max() - s.min()).alias(\n                    \"reader_bingo_duration\"),\n                pl.col(\"index\").filter(((pl.col(\"event_name\") == 'navigate_click') & (pl.col(\"fqid\") == 'reader')) | (\n                            pl.col(\"fqid\") == \"reader.paper2.bingo\")).apply(lambda s: s.max() - s.min()).alias(\n                    \"reader_bingo_indexCount\"),\n                pl.col(\"elapsed_time\").filter(\n                    ((pl.col(\"event_name\") == 'navigate_click') & (pl.col(\"fqid\") == 'journals')) | (\n                                pl.col(\"fqid\") == \"journals.pic_2.bingo\")).apply(lambda s: s.max() - s.min()).alias(\n                    \"journals_bingo_duration\"),\n                pl.col(\"index\").filter(((pl.col(\"event_name\") == 'navigate_click') & (pl.col(\"fqid\") == 'journals')) | (\n                            pl.col(\"fqid\") == \"journals.pic_2.bingo\")).apply(lambda s: s.max() - s.min()).alias(\n                    \"journals_bingo_indexCount\"),\n            ]\n            tmp = x.groupby([\"session_id\"], maintain_order=True).agg(aggs).sort(\"session_id\")\n            df = df.join(tmp, on=\"session_id\", how='left')\n\n        if grp == '13-22':\n            aggs = [\n                pl.col(\"elapsed_time\").filter(\n                    ((pl.col(\"event_name\") == 'navigate_click') & (pl.col(\"fqid\") == 'reader_flag')) | (\n                                pl.col(\"fqid\") == \"tunic.library.microfiche.reader_flag.paper2.bingo\")).apply(\n                    lambda s: s.max() - s.min() if s.len() > 0 else 0).alias(\"reader_flag_duration\"),\n                pl.col(\"index\").filter(\n                    ((pl.col(\"event_name\") == 'navigate_click') & (pl.col(\"fqid\") == 'reader_flag')) | (\n                                pl.col(\"fqid\") == \"tunic.library.microfiche.reader_flag.paper2.bingo\")).apply(\n                    lambda s: s.max() - s.min() if s.len() > 0 else 0).alias(\"reader_flag_indexCount\"),\n                pl.col(\"elapsed_time\").filter(\n                    ((pl.col(\"event_name\") == 'navigate_click') & (pl.col(\"fqid\") == 'journals_flag')) | (\n                                pl.col(\"fqid\") == \"journals_flag.pic_0.bingo\")).apply(\n                    lambda s: s.max() - s.min() if s.len() > 0 else 0).alias(\"journalsFlag_bingo_duration\"),\n                pl.col(\"index\").filter(\n                    ((pl.col(\"event_name\") == 'navigate_click') & (pl.col(\"fqid\") == 'journals_flag')) | (\n                                pl.col(\"fqid\") == \"journals_flag.pic_0.bingo\")).apply(\n                    lambda s: s.max() - s.min() if s.len() > 0 else 0).alias(\"journalsFlag_bingo_indexCount\")\n            ]\n            tmp = x.groupby([\"session_id\"], maintain_order=True).agg(aggs).sort(\"session_id\")\n            df = df.join(tmp, on=\"session_id\", how='left')\n\n    return df.to_pandas()","metadata":{"execution":{"iopub.status.busy":"2023-06-02T05:20:02.702651Z","iopub.execute_input":"2023-06-02T05:20:02.703671Z","iopub.status.idle":"2023-06-02T05:20:02.745859Z","shell.execute_reply.started":"2023-06-02T05:20:02.703631Z","shell.execute_reply":"2023-06-02T05:20:02.744746Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def time_feature(train):\n    train[\"year\"] = train[\"session_id\"].apply(lambda x: int(str(x)[:2])).astype(np.uint8)\n    train[\"month\"] = train[\"session_id\"].apply(lambda x: int(str(x)[2:4])+1).astype(np.uint8)\n    train[\"day\"] = train[\"session_id\"].apply(lambda x: int(str(x)[4:6])).astype(np.uint8)\n    train[\"hour\"] = train[\"session_id\"].apply(lambda x: int(str(x)[6:8])).astype(np.uint8)\n    train[\"minute\"] = train[\"session_id\"].apply(lambda x: int(str(x)[8:10])).astype(np.uint8)\n    train[\"second\"] = train[\"session_id\"].apply(lambda x: int(str(x)[10:12])).astype(np.uint8)\n    return train","metadata":{"execution":{"iopub.status.busy":"2023-06-02T05:20:02.749060Z","iopub.execute_input":"2023-06-02T05:20:02.749675Z","iopub.status.idle":"2023-06-02T05:20:02.764470Z","shell.execute_reply.started":"2023-06-02T05:20:02.749641Z","shell.execute_reply":"2023-06-02T05:20:02.763396Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Train Model","metadata":{}},{"cell_type":"code","source":"from xgboost import XGBClassifier\nfrom lightgbm import LGBMClassifier\nfrom lightgbm import early_stopping\nfrom lightgbm import log_evaluation\n\nfrom sklearn.model_selection import KFold\nfrom sklearn.metrics import roc_auc_score, f1_score\n\ndf1 = train.filter(pl.col(\"level_group\")=='0-4')\ndf2 = train.filter(pl.col(\"level_group\")=='5-12')\ndf3 = train.filter(pl.col(\"level_group\")=='13-22')\nprint(df1.shape,df2.shape,df3.shape)","metadata":{"execution":{"iopub.status.busy":"2023-06-02T05:20:02.766046Z","iopub.execute_input":"2023-06-02T05:20:02.766390Z","iopub.status.idle":"2023-06-02T05:20:05.827413Z","shell.execute_reply.started":"2023-06-02T05:20:02.766359Z","shell.execute_reply":"2023-06-02T05:20:05.826512Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"del train\ngc.collect()","metadata":{"execution":{"iopub.status.busy":"2023-06-02T05:20:05.828377Z","iopub.execute_input":"2023-06-02T05:20:05.828719Z","iopub.status.idle":"2023-06-02T05:20:06.063592Z","shell.execute_reply.started":"2023-06-02T05:20:05.828688Z","shell.execute_reply":"2023-06-02T05:20:06.062680Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(df1.columns)\ndf1 = feature_engineer(df1, grp='0-4', feature_suffix='xgboost')\ndf1.set_index('session_id')\nprint(df1.shape)\ndf2 = feature_engineer(df2, grp='5-12', feature_suffix='xgboost')\ndf2.set_index('session_id')\nprint(df2.shape)\ndf3 = feature_engineer(df3, grp='13-22', feature_suffix='xgboost')\ndf3.set_index('session_id')\nprint(df3.shape)","metadata":{"execution":{"iopub.status.busy":"2023-06-02T05:20:06.064779Z","iopub.execute_input":"2023-06-02T05:20:06.065370Z","iopub.status.idle":"2023-06-02T05:20:57.849437Z","shell.execute_reply.started":"2023-06-02T05:20:06.065336Z","shell.execute_reply":"2023-06-02T05:20:57.848516Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# some cleaning...\n\nnull1 = df1.isnull().sum().sort_values(ascending=False) / len(df1)\n# print(null1.shape)\nnull2 = df2.isnull().sum().sort_values(ascending=False) / len(df1)\nnull3 = df3.isnull().sum().sort_values(ascending=False) / len(df1)\n\ndrop1 = list(null1[null1>0.9].index)\ndrop2 = list(null2[null2>0.9].index)\ndrop3 = list(null3[null3>0.9].index)\nprint(len(drop1), len(drop2), len(drop3))\n\nfor col in df1.columns:\n    if df1[col].nunique()==1:\n        print(col)\n        drop1.append(col)\nprint(\"*********df1 DONE*********\")\nfor col in df2.columns:\n    if df2[col].nunique()==1:\n        print(col)\n        drop2.append(col)\nprint(\"*********df2 DONE*********\")\nfor col in df3.columns:\n    if df3[col].nunique()==1:\n        print(col)\n        drop3.append(col)\nprint(\"*********df3 DONE*********\")","metadata":{"execution":{"iopub.status.busy":"2023-06-02T05:20:57.850662Z","iopub.execute_input":"2023-06-02T05:20:57.850968Z","iopub.status.idle":"2023-06-02T05:21:00.617400Z","shell.execute_reply.started":"2023-06-02T05:20:57.850939Z","shell.execute_reply":"2023-06-02T05:21:00.616293Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"features1 = [c for c in df1.columns if c not in drop1 + ['level_group']]\nfeatures2 = [c for c in df2.columns if c not in drop2 + ['level_group']]\nfeatures3 = [c for c in df3.columns if c not in drop3 + ['level_group']]\n\nusers = df1.index.unique()","metadata":{"execution":{"iopub.status.busy":"2023-06-02T05:21:00.618928Z","iopub.execute_input":"2023-06-02T05:21:00.619538Z","iopub.status.idle":"2023-06-02T05:21:00.749170Z","shell.execute_reply.started":"2023-06-02T05:21:00.619498Z","shell.execute_reply":"2023-06-02T05:21:00.748243Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"choose for some hyper params","metadata":{}},{"cell_type":"code","source":"estimators_xgb = [498, 448, 378, 364, 405, 495, 456, 249, 384, 405, 356, 262, 484, 381, 392, 248 ,248, 345]\nxgb_params = {\n    'booster': 'gbtree',\n    'tree_method': 'hist',\n    'objective': 'binary:logistic',\n    'eval_metric':'logloss',\n    'learning_rate': 0.02,\n    'alpha': 8,\n    'max_depth': 4,\n    'subsample':0.8,\n    'colsample_bytree': 0.5,\n    'seed': 2023\n}\n\ntargets = pd.read_csv('/kaggle/input/predict-student-performance-from-game-play/train_labels.csv')\ntargets['session'] = targets.session_id.apply(lambda x: int(x.split('_')[0]))\ntargets['q'] = targets.session_id.apply(lambda x: int(x.split('_')[-1][1:]))\npred_xgb = np.zeros((df1.shape[0],18))     ","metadata":{"execution":{"iopub.status.busy":"2023-06-02T05:21:00.750673Z","iopub.execute_input":"2023-06-02T05:21:00.750999Z","iopub.status.idle":"2023-06-02T05:21:02.203965Z","shell.execute_reply.started":"2023-06-02T05:21:00.750969Z","shell.execute_reply":"2023-06-02T05:21:02.203028Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for t in range(1, 19):\n    if t <= 3:\n        grp = '0-4'\n        df = df1\n        features = features1 + [f'pre{i}' for i in range(1, t)]\n    elif t <= 13:\n        grp = '5-12'\n        df = df2\n        features = features2 + [f'pre{i}' for i in range(4, t)]\n    else:\n        grp = '13-22'\n        df = df3\n        features = features3 + [f'pre{i}' for i in range(14, t)]\n    train_users = df['session_id']\n    train_y = targets.loc[targets.q == t].set_index('session').loc[train_users]\n\n    xgb_params['n_estimators'] = estimators_xgb[t-1]\n\n    clf =  XGBClassifier(**xgb_params)\n    clf.fit(df[features].astype('float32'), train_y['correct'], verbose = 0)\n    df[f'pre{t}'] = clf.predict_proba(df[features].astype('float32'))[:,1]\n    clf.save_model(f'XGB_question{t}.xgb')\n    \n    print(f'model XGB saved for question {t}')","metadata":{"execution":{"iopub.status.busy":"2023-06-02T05:21:02.205400Z","iopub.execute_input":"2023-06-02T05:21:02.206175Z","iopub.status.idle":"2023-06-02T05:32:17.978083Z","shell.execute_reply.started":"2023-06-02T05:21:02.206142Z","shell.execute_reply":"2023-06-02T05:32:17.977143Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# import jo_wilder_310 as jo_wilder\nimport jo_wilder\nenv = jo_wilder.make_env()\niter_test = env.iter_test()","metadata":{"execution":{"iopub.status.busy":"2023-06-02T05:32:17.991081Z","iopub.execute_input":"2023-06-02T05:32:17.991821Z","iopub.status.idle":"2023-06-02T05:32:18.022896Z","shell.execute_reply.started":"2023-06-02T05:32:17.991769Z","shell.execute_reply":"2023-06-02T05:32:18.021945Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"limits = {'0-4':(1,4), '5-12':(4,14), '13-22':(14,19)}\ncount = 0\n\nfor (test, sample_submission) in iter_test:\n#     print()\n    test = test.sort_values(by = 'index')\n    session_id = test.session_id.values[0]\n    grp = test['level_group'].values[0]\n    a,b = limits[grp]\n    if a == 1:\n        features = features1 \n    elif a == 4:\n        features = features2\n    else:\n        features = features3\n\n    test = pl.from_pandas(test).drop(['fullscreen', 'hq', 'music']).with_columns(columns)\n    test = feature_engineer(test, grp, feature_suffix='xgboost')\n    features_pre = []\n    for t in range(a, b):\n        clf = XGBClassifier()\n        clf.load_model(f\"/kaggle/working/XGB_question{t}.xgb\")\n        mask = sample_submission.session_id.str.contains(f'q{t}')\n        if a == 14 or a == 1:\n            p = clf.predict_proba(test[features+features_pre].astype('float32'))[:, 1]\n        else:\n            p = clf.predict_proba(test[features].astype('float32'))[:, 1]\n        test[f'pre{t}'] = p\n        sample_submission.loc[mask, 'correct'] = int((p.item()) > 0.625)\n        features_pre.append(f'pre{t}')\n    env.predict(sample_submission)","metadata":{"execution":{"iopub.status.busy":"2023-06-02T05:32:18.027398Z","iopub.execute_input":"2023-06-02T05:32:18.029631Z","iopub.status.idle":"2023-06-02T05:32:21.360727Z","shell.execute_reply.started":"2023-06-02T05:32:18.029592Z","shell.execute_reply":"2023-06-02T05:32:21.359834Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(sample_submission)","metadata":{"execution":{"iopub.status.busy":"2023-06-02T05:32:21.362018Z","iopub.execute_input":"2023-06-02T05:32:21.364773Z","iopub.status.idle":"2023-06-02T05:32:21.377356Z","shell.execute_reply.started":"2023-06-02T05:32:21.364735Z","shell.execute_reply":"2023-06-02T05:32:21.376308Z"},"trusted":true},"execution_count":null,"outputs":[]}]}