{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport datatable as dt\nimport gc\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\ntrain_path = \"../input/riiid-test-answer-prediction/train.csv\"\nquestions_path = \"../input/riiid-test-answer-prediction/questions.csv\"\nlectures_path = \"../input/riiid-test-answer-prediction/lectures.csv\"\ntest = \"../input/riiid-test-answer-prediction/example_test.csv\"   \n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"data_types_dict = {\n    'row_id': 'int64', \n    'timestamp': 'int64', \n    'user_id': 'int32', \n    'content_id': 'int16', \n    'content_type_id': 'int8',\n    'task_container_id': 'int16', \n    'user_answer': 'int8', \n    'answered_correctly': 'int8', \n    'prior_question_elapsed_time': 'float32', \n    'prior_question_had_explanation': 'boolean'\n}\ntarget = 'answered_correctly'\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Read data\ntrain_df = pd.read_csv('/kaggle/input/riiid-test-answer-prediction/train.csv',\n                       low_memory=False, \n                       nrows=10**6)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"features = [\n    'prior_question_elapsed_time', \n    'prior_question_had_explanation',\n    'mean_user_acc',\n    'median_user_acc',\n    'std_user_acc',\n    'skew_user_acc',\n    'number_of_answered_q',\n    'mean_task_acc',\n    'median_task_acc',\n    'std_task_acc',\n    'skew_task_acc',\n    'number_of_asked_task_containers',\n    'mean_acc',\n    'median_acc',\n    'std_acc',\n    'skew_acc',\n    'number_of_asked_q',\n#     'user_correctness',\n    'seen_lecture'\n]\n\n\n# drop the unnecessary columns, and only save the last 20 questions answered by each user\n# train_df = train_df.drop(columns=['row_id','timestamp'])\n# train_df = train_df.groupby('user_id').tail(20)\n\n# Replace null\ntrain_df[\"prior_question_elapsed_time\"] = train_df[\"prior_question_elapsed_time\"].replace(np.nan, 0).astype(\"float32\")\ntrain_df[\"prior_question_had_explanation\"] = train_df[\"prior_question_had_explanation\"].replace(np.nan, False).astype(\"boolean\")\ntrain_df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# add the feature seen_lecutre \ndf2 = train_df[['user_id','content_type_id']].drop_duplicates()\ndf2['content_type_id'] = df2.content_type_id.apply(lambda x: 1 if x == 0 else 2)\ndf2 = df2.groupby('user_id').sum().reset_index()\ndf2 = df2.rename(index = str, columns = {\"content_type_id\":\"seen_lecture\"})\ndf2['seen_lecture'] = df2.seen_lecture.apply(lambda x: x-1)\ntrain_df = train_df.merge(df2, how='left', on='user_id')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Exclude lectures\ntrain_df = train_df[train_df[target] != -1].reset_index(drop = True, inplace = False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# construct new features\n# answer for the previous questions\ntrain_df['lag'] = train_df.groupby('user_id')[target].shift()\n# cumulative number of correct answers\ncum = train_df.groupby('user_id')['lag'].agg(['cumsum', 'cumcount'])\n# calculate the correctness\ntrain_df['user_correctness'] = cum['cumsum'] / cum['cumcount']\n# drop the 'lag' feature\ntrain_df.drop(columns = ['lag'], inplace = True)\n\n# Overall correctness of users\nuser_agg = train_df.groupby('user_id')[target].agg(['sum', 'count'])\n# Overall difficulty of questions\ncontent_agg = train_df.groupby('content_id')[target].agg(['sum', 'count'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# merge the question dataset\nquestions_df = pd.read_csv(\n    '../input/riiid-test-answer-prediction/questions.csv', \n    usecols = [0, 3],\n    dtype = {'question_id': 'int16', 'part': 'int8'}\n)\ntrain_df = pd.merge(train_df, questions_df, left_on = 'content_id', right_on = 'question_id', how = 'left')\ntrain_df.drop(columns = ['question_id'], inplace = True)\n\n# How many questions have been answered in each content ID?\n# train_df['content_count'] = train_df['content_id'].map(content_agg['count']).astype('int32')\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"user_characteristics = train_df.groupby('user_id').agg({'answered_correctly':\n                                              ['mean', 'median', 'std', 'skew', 'count']})\nuser_characteristics.columns = [\n    'mean_user_acc',\n    'median_user_acc',\n    'std_user_acc',\n    'skew_user_acc',\n    'number_of_answered_q'\n]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# We saw earlier some dependencies between answered_correctly and the frequency of task_container_id. \n# Therefore I want to add some features for the task_container_id\n# task_container_characteristics derived from task_container_id\ntask_container_characteristics = train_df.groupby('task_container_id').agg({'answered_correctly':\n                                                                      ['mean', 'median', 'std', 'skew', 'count']})\ntask_container_characteristics.columns = [\n    'mean_task_acc',\n    'median_task_acc',\n    'std_task_acc',\n    'skew_task_acc',\n    'number_of_asked_task_containers'\n]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# content_characteristics derived from content_id\ncontent_characteristics = train_df.groupby('content_id').agg({'answered_correctly':\n                                                    ['mean', 'median', 'std', 'skew', 'count']})\ncontent_characteristics.columns = [\n    'mean_acc',\n    'median_acc',\n    'std_acc',\n    'skew_acc',\n    'number_of_asked_q'\n]\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# merge data\ndf = train_df.copy()\ndf = df.merge(user_characteristics, how='left', on='user_id')\ndf = df.merge(task_container_characteristics, how='left', on='task_container_id')\ndf = df.merge(content_characteristics, how='left', on='content_id')\n\ncol_to_drop = set(df.columns.values.tolist()).difference(features + [target])\nfor col in col_to_drop:\n    del df[col]\ndf['prior_question_had_explanation'] = df['prior_question_had_explanation'].fillna(value=False).astype(float)\ndf = df.fillna(value=0.5)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Model training\nimport riiideducation\nfrom sklearn.metrics import roc_auc_score, confusion_matrix\nfrom sklearn.model_selection import train_test_split, GridSearchCV, RandomizedSearchCV, learning_curve\nfrom sklearn.utils import shuffle\nimport lightgbm as lgb\nfrom lightgbm import LGBMClassifier\nimport eli5\nenv = riiideducation.make_env()\ntrain_df, test_df, y_train, y_test = train_test_split(df[features], df[target], random_state=777, test_size=0.2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"params = {\n    'num_leaves': 30, \n    'n_estimators': 300, \n    'min_data_in_leaf': 100, \n    'max_depth': 5, \n    'lambda': 0.0, \n    'feature_fraction': 1.0\n}\nmodel = LGBMClassifier(**params)\nmodel.fit(train_df, y_train)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"eli5.show_weights(model, top=20)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# roc_auc_score(y_test.values, model.predict_proba(test_df)[:, 1])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"iter_test = env.iter_test()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for (test_df, sample_prediction_df) in iter_test:\n    # merge\n    test_df = test_df.merge(user_characteristics, on = \"user_id\", how = \"left\")\n    test_df = test_df.merge(task_container_characteristics, on = \"task_container_id\", how = \"left\")\n    test_df = test_df.merge(content_characteristics, on = \"content_id\", how = \"left\")\n    test_df = pd.merge(test_df, questions_df, left_on = 'content_id', right_on = 'question_id', how = 'left')\n    test_df.drop(columns = ['question_id'], inplace = True)\n    test_df = test_df.merge(df2, how='left', on='user_id')\n    \n \n    \n    # type transformation\n    test_df['prior_question_had_explanation'] = test_df['prior_question_had_explanation'].fillna(value=False).astype(bool)\n    test_df.fillna(value = 0.5, inplace = True)\n    test_df = test_df.replace([np.inf, -np.inf], np.nan)\n    test_df = test_df.fillna(0.5)\n    \n    # preds\n    test_df['answered_correctly'] = model.predict_proba(test_df[features])[:, 1]\n    cols_to_submission = ['row_id', 'answered_correctly', 'group_num']\n    env.predict(test_df.loc[test_df['content_type_id'] == 0, ['row_id', 'answered_correctly']])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","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}