{"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 pickle\nimport numpy as np\nimport pandas as pd","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-05-20T06:11:24.785535Z","iopub.execute_input":"2023-05-20T06:11:24.785945Z","iopub.status.idle":"2023-05-20T06:11:24.832975Z","shell.execute_reply.started":"2023-05-20T06:11:24.785914Z","shell.execute_reply":"2023-05-20T06:11:24.831905Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import jo_wilder_310 as jo_wilder\nenv = jo_wilder.make_env()\niter_test = env.iter_test()","metadata":{"execution":{"iopub.status.busy":"2023-05-20T06:11:24.837614Z","iopub.execute_input":"2023-05-20T06:11:24.839837Z","iopub.status.idle":"2023-05-20T06:11:24.873619Z","shell.execute_reply.started":"2023-05-20T06:11:24.8398Z","shell.execute_reply":"2023-05-20T06:11:24.872291Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"MODEL_DIR = \"/kaggle/input/psp-3-fe-and-train-lgb/\"","metadata":{"execution":{"iopub.status.busy":"2023-05-20T06:11:24.875066Z","iopub.execute_input":"2023-05-20T06:11:24.875385Z","iopub.status.idle":"2023-05-20T06:11:24.88225Z","shell.execute_reply.started":"2023-05-20T06:11:24.875359Z","shell.execute_reply":"2023-05-20T06:11:24.881303Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class FeatureMaker():\n    def __init__(self):\n        self.map_key = None\n        self.valid_keys = None\n        self.list_text_seq = None\n        self.map_text_seq = None\n        self.feature_names = []\n                \n    def prepare(self, df, threshold):\n        # concatenation of variables\n        keys = df[[\"level\", \"name\", \"event_name\", \"room_fqid\", \"fqid\", \"text\"]].values.tolist()\n        keys = [str(values[0]).zfill(2) + \"_\" + \"_\".join([\"None\" if type(v) != str else v for v in values[1:]]) for values in keys]\n        count_keys = Counter(keys)\n        valid_keys = [key for key, value in count_keys.items() if value >= threshold]\n        self.map_key = {key: i for i, key in enumerate(valid_keys)}\n        self.valid_keys = set(valid_keys)\n        \n        # text sequence of important events (notification_click)\n        df_tmp = df.query(\"event_name == 'notification_click'\")[[\"session_id\", \"text\"]].fillna(\"\")\n        df_tmp[\"text_prev\"] = df_tmp.groupby(\"session_id\")[\"text\"].shift()\n        df_tmp = df_tmp.dropna()\n        df_agg = df_tmp.groupby([\"text_prev\", \"text\"], as_index=False).size().sort_values(\"size\", ascending=False)\n        self.list_text_seq = [(text1, text2) for text1, text2 in zip(df_agg[\"text_prev\"], df_agg[\"text\"])]\n        self.map_text_seq = {value: i for i, value in enumerate(self.list_text_seq)}\n        \n        self.feature_names += [f\"count_{key}\" for key in self.map_key.keys()]\n        self.feature_names += [f\"bdiff_{key}\" for key in self.map_key.keys()]\n        self.feature_names += [f\"fdiff_{key}\" for key in self.map_key.keys()]\n        self.feature_names += [f\"time_between_{text1}_and_{text2}\" for text1, text2 in self.list_text_seq]\n        self.feature_names += [\"last_time\", \"diff_level_group_0to1\", \"diff_level_group_1to2\"]\n    \n    def make_feature(self, features, df_session, session_id, level_group):\n        keys = df_session[[\"level\", \"name\", \"event_name\", \"room_fqid\", \"fqid\", \"text\"]].values.tolist()\n        keys = [str(values[0]).zfill(2) + \"_\" + \"_\".join([\"None\" if type(v) != str else v for v in values[1:]]) for values in keys]\n        \n        values_time = df_session[\"elapsed_time\"].tolist()\n        values_event = df_session[\"event_name\"].tolist()\n        values_text = df_session[\"text\"].tolist()\n        \n        # sort by index (dealing with api issue)\n        argsort = np.argsort(df_session[\"index\"].values).tolist()\n        keys = list(map(keys.__getitem__, argsort))\n        values_time = list(map(values_time.__getitem__, argsort))\n        values_event = list(map(values_event.__getitem__, argsort))\n        values_text = list(map(values_text.__getitem__, argsort))\n        \n        # time diff between level_group\n        if level_group == 1:\n            features[-2] = values_time[0] - features[-3]\n        elif level_group == 2:\n            features[-1] = values_time[0] - features[-3]\n        \n        # last time\n        features[-3] = values_time[-1]\n\n        text_prev = \"\"\n        time_prev = 0\n        for i in range(len(df_session)):\n            if keys[i] in self.valid_keys:\n                # count\n                feature_idx = self.map_key[keys[i]]\n                if level_group <= 1:\n                    features[feature_idx] += 1\n                # bdiff\n                feature_idx += len(self.map_key)\n                if level_group <= 1 and i > 0:\n                    features[feature_idx] += values_time[i] - values_time[i-1]\n                # fdiff\n                feature_idx += len(self.map_key)\n                if i < len(df_session) - 1:\n                    features[feature_idx] += values_time[i+1] - values_time[i]\n            # time between important events\n            if values_event[i] == \"notification_click\":\n                if (text_prev, values_text[i]) in self.map_text_seq:\n                    feature_idx = len(self.map_key)*3 + self.map_text_seq[(text_prev, values_text[i])]\n                    features[feature_idx] += values_time[i] - time_prev\n                text_prev = values_text[i]\n                time_prev = values_time[i]\n\n        return features","metadata":{"execution":{"iopub.status.busy":"2023-05-20T06:11:24.88453Z","iopub.execute_input":"2023-05-20T06:11:24.885279Z","iopub.status.idle":"2023-05-20T06:11:24.91109Z","shell.execute_reply.started":"2023-05-20T06:11:24.885246Z","shell.execute_reply":"2023-05-20T06:11:24.909516Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with open(MODEL_DIR + \"feature_maker.pickle\", \"rb\") as f:\n    fm = pickle.load(f)\ndict_feature_index = {f: i for i, f in enumerate(fm.feature_names)}","metadata":{"execution":{"iopub.status.busy":"2023-05-20T06:11:24.913419Z","iopub.execute_input":"2023-05-20T06:11:24.915152Z","iopub.status.idle":"2023-05-20T06:11:24.950447Z","shell.execute_reply.started":"2023-05-20T06:11:24.915115Z","shell.execute_reply":"2023-05-20T06:11:24.949545Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"models = []\nidx_features = [[], [], []]\nvalid_keys = set()\nfor level_group in range(3):\n    with open(MODEL_DIR + f\"model{level_group}.pickle\", \"rb\") as f:\n        model = pickle.load(f)\n    models.append(model)\n    \n    n_features = len(model.feature_name()) \n    df_importance = pd.read_csv(MODEL_DIR + f\"importance{level_group}.csv\")\n    df_importance = df_importance.groupby(\"feature\")[\"importance\"].mean().sort_values(ascending=False)\n    features = df_importance.index[1:n_features-1].tolist()\n    idx_features[level_group] = [dict_feature_index[f] for f in features]\n    valid_keys |= set([f[6:] for f in features if f[:5] in [\"count\", \"bdiff\", \"fdiff\"]])","metadata":{"execution":{"iopub.status.busy":"2023-05-20T06:11:24.951965Z","iopub.execute_input":"2023-05-20T06:11:24.952282Z","iopub.status.idle":"2023-05-20T06:11:28.378479Z","shell.execute_reply.started":"2023-05-20T06:11:24.952252Z","shell.execute_reply":"2023-05-20T06:11:28.377448Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fm.valid_keys = valid_keys","metadata":{"execution":{"iopub.status.busy":"2023-05-20T06:11:28.37963Z","iopub.execute_input":"2023-05-20T06:11:28.380254Z","iopub.status.idle":"2023-05-20T06:11:28.384445Z","shell.execute_reply.started":"2023-05-20T06:11:28.380224Z","shell.execute_reply":"2023-05-20T06:11:28.383392Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"n_questions = [3, 10, 5]\nquestions = [\n    np.array([1, 2, 3], dtype=np.float32),\n    np.array([4, 5, 6, 7, 8, 9, 10, 11, 12, 13], dtype=np.float32),\n    np.array([14, 15, 16, 17, 18], dtype=np.float32)\n]","metadata":{"execution":{"iopub.status.busy":"2023-05-20T06:11:28.385567Z","iopub.execute_input":"2023-05-20T06:11:28.386091Z","iopub.status.idle":"2023-05-20T06:11:28.398869Z","shell.execute_reply.started":"2023-05-20T06:11:28.386062Z","shell.execute_reply":"2023-05-20T06:11:28.397946Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"threshold = 0.625","metadata":{"execution":{"iopub.status.busy":"2023-05-20T06:11:28.401275Z","iopub.execute_input":"2023-05-20T06:11:28.401789Z","iopub.status.idle":"2023-05-20T06:11:28.411917Z","shell.execute_reply.started":"2023-05-20T06:11:28.40176Z","shell.execute_reply":"2023-05-20T06:11:28.411101Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dict_features = dict()\nfor df_session, df_pred in iter_test:\n    session_id = df_session.iloc[0, 0]\n    if len(df_pred) == 3:\n        level_group = 0\n    elif len(df_pred) == 10:\n        level_group = 1\n    elif len(df_pred) == 5:\n        level_group = 2\n    \n    if level_group == 0:\n        dict_features[session_id] = [0] * len(fm.feature_names)\n    dict_features[session_id] = fm.make_feature(dict_features[session_id], df_session, session_id, level_group)\n    X_test = list(map(dict_features[session_id].__getitem__, idx_features[level_group]))\n    X_test = np.array([0] + [value if value != 0 else np.nan for value in X_test] + [22], dtype=np.float32)  # append \"q\" and \"level_max\"\n    X_test = np.tile(X_test, (n_questions[level_group], 1))\n    X_test[:, 0] = questions[level_group]\n    preds = (models[level_group].predict(X_test) > threshold).astype(int)\n    \n    # overwrite the session_id values (dealing with api issue)\n    df_pred[\"session_id\"] = [f\"{session_id}_q{int(q)}\" for q in questions[level_group]]\n    df_pred[\"correct\"] = preds\n    env.predict(df_pred)","metadata":{"execution":{"iopub.status.busy":"2023-05-20T06:11:28.413189Z","iopub.execute_input":"2023-05-20T06:11:28.413699Z","iopub.status.idle":"2023-05-20T06:11:28.54058Z","shell.execute_reply.started":"2023-05-20T06:11:28.413649Z","shell.execute_reply":"2023-05-20T06:11:28.539453Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"## the end result is a submission file containing all test session predictions\n! head submission.csv","metadata":{"execution":{"iopub.status.busy":"2023-05-20T06:11:28.544748Z","iopub.execute_input":"2023-05-20T06:11:28.545086Z","iopub.status.idle":"2023-05-20T06:11:29.646198Z","shell.execute_reply.started":"2023-05-20T06:11:28.545058Z","shell.execute_reply":"2023-05-20T06:11:29.644746Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_pred = pd.read_csv(\"submission.csv\")\ndf_pred[\"correct\"].value_counts()","metadata":{"execution":{"iopub.status.busy":"2023-05-20T06:11:29.65049Z","iopub.execute_input":"2023-05-20T06:11:29.650913Z","iopub.status.idle":"2023-05-20T06:11:29.670265Z","shell.execute_reply.started":"2023-05-20T06:11:29.650878Z","shell.execute_reply":"2023-05-20T06:11:29.669197Z"},"trusted":true},"execution_count":null,"outputs":[]}]}