{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nimport pickle\nfrom collections import defaultdict\nfrom vowpalwabbit import pyvw\nfrom datetime import datetime\nfrom sklearn.metrics import roc_auc_score","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"# Get mean by each question id - with low memory usage\nquestion_ratings = []\nfor chunk in pd.read_csv(\"/kaggle/input/riiid-test-answer-prediction/train.csv\", chunksize=1000000):\n    chunk = chunk[chunk.answered_correctly != -1].copy()\n    chunk.answered_correctly = chunk.answered_correctly.astype('bool')            \n    chunk = chunk.groupby('content_id').answered_correctly.agg(['count', 'sum'])\n    question_ratings.append(chunk)\nquestion_ratings = pd.concat(question_ratings)\nquestion_ratings = question_ratings.groupby(level = 0).agg('sum')\nquestion_ratings['questions_mean'] = question_ratings['sum'] / question_ratings['count']\nquestion_ratings.drop(columns = ['sum', 'count'], inplace=True)\nprint(question_ratings)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"questions_dict = pd.read_csv('/kaggle/input/riiid-test-answer-prediction/questions.csv', index_col='question_id')\nquestions_dict = questions_dict.join(question_ratings)\nquestions_dict = questions_dict.apply(lambda row: f'|q_params mean:{row[\"questions_mean\"]} part:{row[\"part\"]} {row[\"tags\"]}', axis=1)\nprint(questions_dict)\nquestions_dict = questions_dict.to_dict()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"lectures_dict = pd.read_csv('/kaggle/input/riiid-test-answer-prediction/lectures.csv', index_col='lecture_id')\nlectures_dict = lectures_dict.apply(lambda row: f'|l_params tag:{row[\"tag\"]} part:{row[\"part\"]} type_of:{row[\"type_of\"]}', axis=1)\nprint(lectures_dict)\nlectures_dict = lectures_dict.to_dict()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class vv_user_class:\n    def __init__(self):\n        self.lectures = []\n        self.lectures_str = ''\n        self.lectures_tags_str = ''\n        \n        self.questions = []\n        self.questions_str = ''\n\n    def get_features(self, user_id, content_id, content_type_id, timestamp, prior_question_elapsed_time, prior_question_had_explanation):       \n        l_last = lectures_dict[self.lectures[-1]] if len(self.lectures) > 0 else ''        \n#       result = f'|q_hist {self.questions_str} |l_hist {self.lectures_str} |q {questions_dict[content_id]} |l {l_last} |user {user_id} |question {content_id}'\n        result = f'|q_hist {self.questions_str} |l_hist {self.lectures_str} {questions_dict[content_id]} {l_last} |user {user_id} |question {content_id} f1:{prior_question_elapsed_time} f2:{prior_question_had_explanation}'\n        return result\n    \n    def update_question(self, answered_correctly, user_id, content_id, content_type_id, timestamp, prior_question_elapsed_time, prior_question_had_explanation):\n        self.questions_str += f' {content_id}:{1 if answered_correctly else -0.1}'\n    \n    def update_lecture(self, answered_correctly, user_id, content_id, content_type_id, timestamp):\n        self.lectures.append(content_id)\n        self.lectures_str += f' {content_id}'\n\nclass vw_generator_str_class:\n    def __init__(self):\n        self.model = pyvw.vw(random_seed=17, loss_function='logistic', link='logistic', quiet=True)\n        self.users = defaultdict(vv_user_class)\n\n    def train(self, train_df):\n        for idx, (user_id, content_id, content_type_id, answered_correctly, timestamp, prior_question_elapsed_time, prior_question_had_explanation)\\\n                in enumerate(zip(train_df.user_id, train_df.content_id, train_df.content_type_id, train_df.answered_correctly, train_df.timestamp, train_df.prior_question_elapsed_time, train_df.prior_question_had_explanation)):\n            user = self.users[user_id]\n\n            if content_type_id == 0:\n                self.model.learn(str(answered_correctly*2-1) + ' ' + user.get_features(user_id, content_id, content_type_id, timestamp, prior_question_elapsed_time, prior_question_had_explanation))\n                user.update_question(answered_correctly, user_id, content_id, content_type_id, timestamp, prior_question_elapsed_time, prior_question_had_explanation)\n            else:\n                user.update_lecture(answered_correctly, user_id, content_id, content_type_id, timestamp)\n\n    def predict_than_train(self, train_df):\n        prediction_list = []\n        for idx, (user_id, content_id, content_type_id, answered_correctly, timestamp, prior_question_elapsed_time, prior_question_had_explanation) \\\n                in enumerate(zip(train_df.user_id, train_df.content_id, train_df.content_type_id, train_df.answered_correctly, train_df.timestamp, train_df.prior_question_elapsed_time, train_df.prior_question_had_explanation)):\n            user = self.users[user_id]\n\n            if content_type_id == 0:\n                prediction_list.append(self.model.predict(user.get_features(user_id, content_id, content_type_id, timestamp, prior_question_elapsed_time, prior_question_had_explanation)))\n                self.model.learn(str(answered_correctly*2-1) + ' ' + user.get_features(user_id, content_id, content_type_id, timestamp, prior_question_elapsed_time, prior_question_had_explanation))\n                user.update_question(answered_correctly, user_id, content_id, content_type_id, timestamp, prior_question_elapsed_time, prior_question_had_explanation)\n            else:\n                prediction_list.append(-1)\n                user.update_lecture(answered_correctly, user_id, content_id, content_type_id, timestamp)\n        return prediction_list\n    \n    def predict(self, test_df):\n        prediction_list = []\n        for idx, (user_id, content_id, content_type_id, timestamp, prior_question_elapsed_time, prior_question_had_explanation) \\\n                in enumerate(zip(test_df.user_id, test_df.content_id, test_df.content_type_id, test_df.timestamp, test_df.prior_question_elapsed_time, test_df.prior_question_had_explanation)):\n            user = self.users[user_id]\n\n            if content_type_id == 0:\n                prediction_list.append(self.model.predict(user.get_features(user_id, content_id, content_type_id, timestamp, prior_question_elapsed_time, prior_question_had_explanation)))\n            else:\n                prediction_list.append(-1)\n        return prediction_list","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Train the model by chunks"},{"metadata":{"trusted":true},"cell_type":"code","source":"vw_generator = vw_generator_str_class()\nfor id, chunk in enumerate(pd.read_csv(\"/kaggle/input/riiid-test-answer-prediction/train.csv\", chunksize=500000)):\n    start_time = datetime.now()\n    chunk.answered_correctly = chunk.answered_correctly.astype('bool')  \n    chunk.prior_question_elapsed_time.fillna(0, inplace = True)\n    chunk.prior_question_had_explanation.fillna(True, inplace = True)\n    \n    if id % 10 == 0:\n        chunk['answered_correctly_pred'] = vw_generator.predict_than_train(chunk)\n        chunk = chunk[chunk.content_type_id == 0]\n        print(f'chunk {id} done duration={datetime.now() - start_time} auc={roc_auc_score(chunk.answered_correctly, chunk.answered_correctly_pred)}')\n    else:\n        vw_generator.train(chunk)\n        print(f'chunk {id} done duration={datetime.now() - start_time}')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Prediction"},{"metadata":{"trusted":true},"cell_type":"code","source":"import riiideducation\nenv = riiideducation.make_env()\n\ntest_df_prev = pd.DataFrame()\niter_test = env.iter_test()\n\nstart_time = datetime.now()\nfor (test_df, sample_prediction_df) in iter_test: \n    iter_start_time = datetime.now()\n    \n    # Update model from previous iteration\n    if len(test_df_prev) != 0:\n        answered_correctly = test_df.iloc[0].prior_group_answers_correct.strip('[]').split(',')\n        answered_correctly = [int(i.strip()) for i in answered_correctly] \n        answered_correctly = np.array(answered_correctly)\n        test_df_prev['answered_correctly'] = answered_correctly\n        \n        vw_generator.train(test_df_prev)\n\n    # Prediction for current iteration\n    test_df['answered_correctly'] = vw_generator.predict(test_df)\n    env.predict(test_df.loc[test_df['content_type_id'] == 0, ['row_id', 'answered_correctly']])\n    \n    test_df_prev = test_df.copy()\n    print('Duration iter: {}'.format(datetime.now() - iter_start_time))\n    \nprint('Duration total: {}'.format(datetime.now() - start_time))","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}