{"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":"import pandas as pd\nimport numpy as np\nfrom tensorflow import keras\nimport tensorflow as tf\nfrom sklearn.model_selection import GroupKFold\nfrom sklearn.metrics import f1_score","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-02-21T08:29:50.754516Z","iopub.execute_input":"2023-02-21T08:29:50.754840Z","iopub.status.idle":"2023-02-21T08:29:50.760056Z","shell.execute_reply.started":"2023-02-21T08:29:50.754816Z","shell.execute_reply":"2023-02-21T08:29:50.759247Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train = pd.read_csv('/kaggle/input/predict-student-performance-from-game-play/train.csv')\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:]) )\nprint( targets.shape )\ntargets.head()","metadata":{"execution":{"iopub.status.busy":"2023-02-21T08:29:50.761881Z","iopub.execute_input":"2023-02-21T08:29:50.762415Z","iopub.status.idle":"2023-02-21T08:30:58.214809Z","shell.execute_reply.started":"2023-02-21T08:29:50.762377Z","shell.execute_reply":"2023-02-21T08:30:58.212666Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"CATS = ['event_name', 'fqid', 'room_fqid', 'text']\nNUMS = ['elapsed_time','level','page','room_coor_x', 'room_coor_y', \n        'screen_coor_x', 'screen_coor_y', 'hover_duration']\n\n# https://www.kaggle.com/code/kimtaehun/lightgbm-baseline-with-aggregated-log-data\nEVENTS = ['navigate_click','person_click','cutscene_click','object_click',\n          'map_hover','notification_click','map_click','observation_click',\n          'checkpoint']","metadata":{"execution":{"iopub.status.busy":"2023-02-21T08:30:58.217449Z","iopub.execute_input":"2023-02-21T08:30:58.219411Z","iopub.status.idle":"2023-02-21T08:30:58.228570Z","shell.execute_reply.started":"2023-02-21T08:30:58.219324Z","shell.execute_reply":"2023-02-21T08:30:58.226398Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def feature_engineer(train):\n    \n    dfs = []\n    for c in CATS:\n        tmp = train.groupby(['session_id','level_group'])[c].agg('nunique')\n        tmp.name = tmp.name + '_nunique'\n        dfs.append(tmp)\n    for c in NUMS:\n        tmp = train.groupby(['session_id','level_group'])[c].agg('mean')\n        tmp.name = tmp.name + '_mean'\n        dfs.append(tmp)\n    for c in NUMS:\n        tmp = train.groupby(['session_id','level_group'])[c].agg('std')\n        tmp.name = tmp.name + '_std'\n        dfs.append(tmp)\n    for c in EVENTS: \n        train[c] = (train.event_name == c).astype('int8')\n    for c in EVENTS + ['elapsed_time']:\n        tmp = train.groupby(['session_id','level_group'])[c].agg('sum')\n        tmp.name = tmp.name + '_sum'\n        dfs.append(tmp)\n    train = train.drop(EVENTS,axis=1)\n        \n    df = pd.concat(dfs,axis=1)\n    df = df.fillna(-1)\n    df = df.reset_index()\n    df = df.set_index('session_id')\n    return df","metadata":{"execution":{"iopub.status.busy":"2023-02-21T08:30:58.232027Z","iopub.execute_input":"2023-02-21T08:30:58.232378Z","iopub.status.idle":"2023-02-21T08:30:58.255607Z","shell.execute_reply.started":"2023-02-21T08:30:58.232336Z","shell.execute_reply":"2023-02-21T08:30:58.253795Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = feature_engineer(train)\nprint( df.shape )\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2023-02-21T08:30:58.257997Z","iopub.execute_input":"2023-02-21T08:30:58.258465Z","iopub.status.idle":"2023-02-21T08:31:51.243793Z","shell.execute_reply.started":"2023-02-21T08:30:58.258423Z","shell.execute_reply":"2023-02-21T08:31:51.241898Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"FEATURES = [c for c in df.columns if c != 'level_group']\nprint('We will train with', len(FEATURES) ,'features')\nALL_USERS = df.index.unique()\nprint('We will train with', len(ALL_USERS) ,'users info')","metadata":{"execution":{"iopub.status.busy":"2023-02-21T08:31:51.246642Z","iopub.execute_input":"2023-02-21T08:31:51.247134Z","iopub.status.idle":"2023-02-21T08:31:51.258926Z","shell.execute_reply.started":"2023-02-21T08:31:51.247092Z","shell.execute_reply":"2023-02-21T08:31:51.257171Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"gkf = GroupKFold(n_splits=5)\noof = pd.DataFrame(data=np.zeros((len(ALL_USERS),18)), index=ALL_USERS)\nmodels = {}\n\n\n# COMPUTE CV SCORE WITH 5 GROUP K FOLD\nfor i, (train_index, test_index) in enumerate(gkf.split(X=df, groups=df.index)):\n    \n    print('#'*25)\n    print('### Fold',i+1)\n    print('#'*25)\n    \n    # ITERATE THRU QUESTIONS 1 THRU 18\n    for t in range(1,19):\n        \n        print(f'performing question {t}')\n        \n        # USE THIS TRAIN DATA WITH THESE QUESTIONS\n        if t<=3: grp = '0-4'\n        elif t<=13: grp = '5-12'\n        elif t<=22: grp = '13-22'\n            \n        # TRAIN DATA\n        train_x = df.iloc[train_index]\n        train_x = train_x.loc[train_x.level_group == grp]\n        train_users = train_x.index.values\n        train_y = targets.loc[targets.q==t].set_index('session').loc[train_users]\n        \n        # VALID DATA\n        valid_x = df.iloc[test_index]\n        valid_x = valid_x.loc[valid_x.level_group == grp]\n        valid_users = valid_x.index.values\n        valid_y = targets.loc[targets.q==t].set_index('session').loc[valid_users]\n        \n        # CLEARING Backend before every NN\n        keras.backend.clear_session()\n    \n        \n        model = keras.models.Sequential([\n            keras.layers.Dense(32, activation=\"elu\"),\n            keras.layers.Dropout(0.5),\n            keras.layers.Dense(16, activation=\"elu\"),\n            keras.layers.Dropout(0.25),\n            keras.layers.Dense(1, activation=\"sigmoid\")\n        ])\n\n        model.compile(loss='binary_crossentropy',\n        optimizer=keras.optimizers.Nadam(learning_rate=0.05), \n        metrics=['accuracy']\n        )\n\n        history = model.fit(train_x[FEATURES].astype('float32'), train_y['correct'], epochs=10, verbose = 0)\n        \n        \n        # SAVE MODEL, PREDICT VALID OOF\n        models[f'{grp}_{t}'] = model\n        pp = model.predict(valid_x[FEATURES].astype('float32'))\n        new_arr = np.hstack((np.zeros(pp.shape), pp))\n        oof.loc[valid_users, t-1] = new_arr[:,1]\n        \n    print()","metadata":{"execution":{"iopub.status.busy":"2023-02-21T08:31:51.261203Z","iopub.execute_input":"2023-02-21T08:31:51.262046Z","iopub.status.idle":"2023-02-21T08:47:32.286399Z","shell.execute_reply.started":"2023-02-21T08:31:51.261988Z","shell.execute_reply":"2023-02-21T08:47:32.285166Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# PUT TRUE LABELS INTO DATAFRAME WITH 18 COLUMNS\ntrue = oof.copy()\nfor k in range(18):\n    # GET TRUE LABELS\n    tmp = targets.loc[targets.q == k+1].set_index('session').loc[ALL_USERS]\n    true[k] = tmp.correct.values","metadata":{"execution":{"iopub.status.busy":"2023-02-21T08:47:32.287847Z","iopub.execute_input":"2023-02-21T08:47:32.288307Z","iopub.status.idle":"2023-02-21T08:47:32.361826Z","shell.execute_reply.started":"2023-02-21T08:47:32.288279Z","shell.execute_reply":"2023-02-21T08:47:32.360605Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# FIND BEST THRESHOLD TO CONVERT PROBS INTO 1s AND 0s\nscores = []; thresholds = []\nbest_score = 0; best_threshold = 0\n\nfor threshold in np.arange(0.4,0.81,0.01):\n    print(f'{threshold:.02f}, ',end='')\n    preds = (oof.values.reshape((-1))>threshold).astype('int')\n    m = f1_score(true.values.reshape((-1)), preds, average='macro')   \n    scores.append(m)\n    thresholds.append(threshold)\n    if m>best_score:\n        best_score = m\n        best_threshold = threshold","metadata":{"execution":{"iopub.status.busy":"2023-02-21T08:47:32.363134Z","iopub.execute_input":"2023-02-21T08:47:32.363638Z","iopub.status.idle":"2023-02-21T08:47:34.479237Z","shell.execute_reply.started":"2023-02-21T08:47:32.363610Z","shell.execute_reply":"2023-02-21T08:47:34.477754Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n# PLOT THRESHOLD VS. F1_SCORE\nplt.figure(figsize=(20,5))\nplt.plot(thresholds,scores,'-o',color='blue')\nplt.scatter([best_threshold], [best_score], color='blue', s=300, alpha=1)\nplt.xlabel('Threshold',size=14)\nplt.ylabel('Validation F1 Score',size=14)\nplt.title(f'Threshold vs. F1_Score with Best F1_Score = {best_score:.3f} at Best Threshold = {best_threshold:.3}',size=18)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-02-21T08:47:34.482124Z","iopub.execute_input":"2023-02-21T08:47:34.482512Z","iopub.status.idle":"2023-02-21T08:47:34.713777Z","shell.execute_reply.started":"2023-02-21T08:47:34.482481Z","shell.execute_reply":"2023-02-21T08:47:34.712615Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('When using optimal threshold...')\nfor k in range(18):\n        \n    # COMPUTE F1 SCORE PER QUESTION\n    m = f1_score(true[k].values, (oof[k].values>best_threshold).astype('int'), average='macro')\n    print(f'Q{k}: F1 =',m)\n    \n# COMPUTE F1 SCORE OVERALL\nm = f1_score(true.values.reshape((-1)), (oof.values.reshape((-1))>best_threshold).astype('int'), average='macro')\nprint('==> Overall F1 =',m)","metadata":{"execution":{"iopub.status.busy":"2023-02-21T08:47:34.715270Z","iopub.execute_input":"2023-02-21T08:47:34.715626Z","iopub.status.idle":"2023-02-21T08:47:34.833679Z","shell.execute_reply.started":"2023-02-21T08:47:34.715599Z","shell.execute_reply":"2023-02-21T08:47:34.832264Z"},"trusted":true},"execution_count":null,"outputs":[]}]}