{"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 os\nimport numpy as np\nimport pandas as pd\nimport lightgbm as lgb\nfrom sklearn.model_selection import GroupKFold\nfrom sklearn.metrics import f1_score\nCATS = [\"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\"]\nEVENTS = [\"navigate_click\", \"person_click\", \"cutscene_click\", \"object_click\",\n          \"map_hover\", \"notification_click\", \"map_click\", \"observation_click\", \"checkpoint\"]\nLEVEL_GROUPS = [\"0-4\", \"5-12\", \"13-22\"]\n\nDATA_DIR = None\nfor candidate in [\n    \"/kaggle/input/predict-student-performance-from-game-play\",\n    \"../input/predict-student-performance-from-game-play\"\n]:\n    if os.path.exists(candidate):\n        DATA_DIR = candidate\n        break\nassert DATA_DIR is not None, f\"找不到数据集目录:{os.listdir('/kaggle/input') if os.path.exists('/kaggle/input') else '.'}\"\ndef agg_features(df):\n    agg_dict = {}\n    for c in CATS:\n        agg_dict[c] = \"nunique\"\n    for c in NUMS:\n        agg_dict[c] = [\"mean\", \"std\"]\n    for c in EVENTS:\n        col = f\"{c}_elapsed\"\n        agg_dict[col] = \"sum\"\n    df_agg = df.groupby([\"session_id\", \"level_group\"]).agg(agg_dict).reset_index()\n    new_cols = [\"session_id\", \"level_group\"]\n    for k, v_list in agg_dict.items():\n        if isinstance(v_list, list):\n            for v in v_list:\n                new_cols.append(f\"{k}_{v}\")\n        else:\n            new_cols.append(f\"{k}_{v_list}\")\n    df_agg.columns = new_cols\n    return df_agg\n\ndef build_cum_feature(df_all):\n    df_04 = df_all[df_all[\"level_group\"] == \"0-4\"].copy()\n    df_512 = df_all[df_all[\"level_group\"] == \"5-12\"].copy()\n    df_1322 = df_all[df_all[\"level_group\"] == \"13-22\"].copy()\n\n    feat_cols = [c for c in df_all.columns if c not in [\"session_id\", \"level_group\"]]\n    # 5-12拼接0-4历史\n    map_04 = df_04.set_index(\"session_id\")[feat_cols]\n    for col in feat_cols:\n        df_512[f\"pre04_{col}\"] = df_512[\"session_id\"].map(map_04[col])\n    # 13-22拼接04+512\n    map_512 = df_512.set_index(\"session_id\")[feat_cols]\n    for col in feat_cols:\n        df_1322[f\"pre04_{col}\"] = df_1322[\"session_id\"].map(map_04[col])\n        df_1322[f\"pre512_{col}\"] = df_1322[\"session_id\"].map(map_512[col])\n\n    out = pd.concat([df_04, df_512, df_1322], axis=0).fillna(-1)\n    return out\n\ntargets = pd.read_csv(os.path.join(DATA_DIR, \"train_labels.csv\"))\ntargets[\"session\"] = targets[\"session_id\"].apply(lambda x: x.split(\"_\")[0])\ntarget_map = dict(zip(targets[\"session\"], targets[\"correct\"]))\n\ndtype_spec = {\n    \"session_id\": \"category\",\n    \"level_group\": \"category\",\n    \"elapsed_time\": \"int32\"\n}\ndf_raw = pd.read_csv(os.path.join(DATA_DIR, \"train.csv\"), dtype=dtype_spec)\n\nevent_dummy = pd.get_dummies(df_raw[\"event_name\"], prefix=\"\").astype(\"int8\")\ndf_raw = pd.concat([df_raw, event_dummy], axis=1)\ndf_agg = agg_features(df_raw)\ndf_final = build_cum_feature(df_agg)\n\ndf_final[\"session\"] = df_final[\"session_id\"].apply(lambda x: x.split(\"_\")[0])\ndf_final[\"correct\"] = df_final[\"session\"].map(target_map)\nuse_feats = [c for c in df_final.columns if c not in [\"session_id\", \"level_group\", \"session\", \"correct\"]]\nX = df_final[use_feats].values\ny = df_final[\"correct\"].values\ngroup_arr = df_final[\"session\"].values\ngkf = GroupKFold(n_splits=5)\noof = np.zeros(len(X))\nbest_th = 0.5\nfor tr_idx, val_idx in gkf.split(X, y, groups=group_arr):\n    Xtr, Xval = X[tr_idx], X[val_idx]\n    ytr, yval = y[tr_idx], y[val_idx]\n\n    clf = lgb.LGBMClassifier(\n        n_estimators=1200,\n        learning_rate=0.025,\n        subsample=0.8,\n        colsample_bytree=0.8,\n        random_state=42,\n        verbose=-1\n    )\n    clf.fit(\n        Xtr, ytr,\n        eval_set=[(Xval, yval)],\n        callbacks=[lgb.early_stopping(60)]\n    )\n    oof[val_idx] = clf.predict_proba(Xval)[:, 1]\n\nth_candidates = np.linspace(0, 1, 100)\nf1_list = []\nfor th in th_candidates:\n    pred_tmp = (oof > th).astype(int)\n    f1_list.append(f1_score(y, pred_tmp, average=\"macro\"))\nbest_th = th_candidates[np.argmax(f1_list)]\nprint(f\"最优阈值:{best_th:.3f},最优F1:{max(f1_list):.4f}\")\ndef predict_test(test_df):\n    # 同训练集特征流水线\n    event_dummy = pd.get_dummies(test_df[\"event_name\"], prefix=\"\").astype(\"int8\")\n    test_df = pd.concat([test_df, event_dummy], axis=1)\n    agg_df = agg_features(test_df)\n    cum_df = build_cum_feature(agg_df)\n    X_test = cum_df[use_feats].fillna(-1).values\n    pred_prob = clf.predict_proba(X_test)[:,1]\n    pred = (pred_prob > best_th).astype(int)\n    return pred\n\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"","metadata":{}}]}