{"cells":[{"metadata":{"trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\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\n# You can write up to 5GB 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":{"trusted":true},"cell_type":"code","source":"\"\"\"\nCreated on Mon Oct  5 22:50:40 2020\n\n@author: André\n\"\"\"\n# =============================================================================\n# IMPORT NECESSARY LIBRARIES\n# =============================================================================\n\n#Core libraries\nimport pandas as pd\nimport numpy as np\nimport math\n\n#Data loading\nfrom sklearn.model_selection import train_test_split\n\n#Preprocessing\nfrom sklearn import preprocessing\nfrom sklearn.impute import SimpleImputer\nfrom sklearn.compose import ColumnTransformer\n\n#Modeling\nfrom sklearn.ensemble import RandomForestRegressor\n\n#Pipeline\nfrom sklearn.pipeline import Pipeline\n\n#Validation\nimport sklearn.metrics as metrics\nfrom sklearn.metrics import roc_auc_score\n\n#Visualization\nimport seaborn as sns\nimport matplotlib.pyplot as plt","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# =============================================================================\n# DATA LOADING\n# =============================================================================\n\n#Filepath of relevant files\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'\n\n#Load relevant files\ntrain_df = pd.read_csv(train_path, nrows = 100000).set_index('row_id') #train.csv too big, lets load 100k rows for now\ntrain_df = train_df.loc[train_df['content_type_id'] == 0] #this is also a bit of a hack\ny = train_df['answered_correctly']\ntrain_df = train_df.drop('answered_correctly', axis = 1)\n \nquestions_df = pd.read_csv(questions_path).set_index('question_id')\nlectures_df = pd.read_csv(lectures_path).set_index('lecture_id')\n\n\n#Create calculated dataframes and calculated columns\nuser_features = ['user_id', 'user_rating']\nusers_df = pd.DataFrame(columns = user_features).set_index('user_id')\nquestions_df['question_rating'] = np.NaN\n\n#Train/test split\nX_train, X_valid, y_train, y_valid = train_test_split(train_df, y)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# =============================================================================\n# PREPROCESSING\n# =============================================================================\n\nidentity_transformer = SimpleImputer(strategy = 'constant', fill_value = 0)\n\nrating_transformer = SimpleImputer(strategy = 'constant', fill_value = 500)\n\ntrain_preprocessor = ColumnTransformer(\n        transformers = [\n                ('id', identity_transformer, ['user_id', 'content_id', 'content_type_id'])\n                ])\n\ntest_preprocessor = ColumnTransformer(\n        transformers = [\n                ('id', identity_transformer, ['row_id', 'user_id', 'content_id', 'content_type_id'])\n                ])\n\nquestions_preprocessor = ColumnTransformer(\n        transformers = [\n                ('rating', rating_transformer, ['question_rating'])\n                ])\n\ntrain_features = ['user_id', 'content_id', 'content_type_id']\ntest_features = ['row_id', 'user_id', 'content_id', 'content_type_id']\nquestion_features = ['question_rating']\nfeatures = ['user_rating', 'question_rating']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# =============================================================================\n# FEATURE CREATING\n# =============================================================================\n\ndef train_rating_model(X, y, users, questions):\n      \n    for index, row in X.iterrows():\n        \n        #Calculate expected outcoume\n        ur = users.loc[row['user_id'], 'user_rating']\n        cr = questions.loc[row['content_id'], 'question_rating']\n        ea = 1/(1 + math.pow(10, (cr - ur)/400))\n        \n        #Update rating based on real values\n        users.loc[row['user_id'], 'user_rating'] += 32*(y.loc[index] - ea)\n        questions.loc[row['content_id'], 'question_rating'] += 32*(ea - y.loc[index])\n        \n    return users, questions\n\n\ndef reg_new_users_and_questions(X, users, questions):\n    \n    for index, row in X.iterrows():\n        \n        #If user is new, add to dataframe\n        if not (row['user_id'] in users.index):\n            new_user = pd.DataFrame({\"user_rating\": 500}, index=[row['user_id']])\n            #FIX: this is bad, because I need to recode everytime I change features\n            \n            users = pd.concat([users, new_user])\n            \n        if not (row['content_id'] in questions.index):\n            new_question = pd.DataFrame({\"question_rating\": 392}, index=[row['content_id']])\n            #FIX: this is bad, because I need to recode everytime I change features\n            \n            questions = pd.concat([questions, new_question])\n\n    return users, questions\n\n\ndef update_ratings(X, y, preds, users, questions):\n    \n    for index, row in X.iterrows():\n        \n        ea = preds[index]\n        users.loc[row['user_id'], 'user_rating'] += 32*(y.loc[index] - ea)\n        questions.loc[row['content_id'], 'question_rating'] += 32*(ea - y.loc[index])\n        \n    return users, questions","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# =============================================================================\n# MODELING FUNCTIONS\n# =============================================================================\n\n\ndef predict_based_on_rating(X):\n    \n    preds = []\n    for index, row in X.iterrows():\n        preds.append(1/(1 + math.pow(10, (row['question_rating'] - row['user_rating'])/400)))\n    \n    return pd.Series(data = preds, index = X.index)\n    \n\nmodel_1 = RandomForestRegressor()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# =============================================================================\n# TRAINING\n# =============================================================================\n\n#Preprocess data\nX_train = pd.DataFrame(train_preprocessor.fit_transform(X_train), index = X_train.index ,columns = train_features)\nquestions_df = pd.DataFrame(questions_preprocessor.fit_transform(questions_df), index = questions_df.index, columns = question_features)\n\n\n#Construct features\nusers_df, questions_df = reg_new_users_and_questions(X_train, users_df, questions_df)\nusers_df, questions_df = train_rating_model(X_train, y_train, users_df, questions_df)\nusers_df, questions_df = train_rating_model(X_train, y_train, users_df, questions_df) #double time :D\n\n#Train model\nX_train = X_train.join(users_df, on = 'user_id')\nX_train = X_train.join(questions_df, on = 'content_id')\nmodel_1 = model_1.fit(X_train[features], y_train)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# =============================================================================\n# SUBMISSION\n# =============================================================================\n\n# I should be trainign my model with the whole data before proceeding\n\n#first iter\nimport riiideducation\nenv = riiideducation.make_env()\n\niter_test = env.iter_test()\n\n(test_df, sample_prediction_df) = next(iter_test)\n\n#Preprocess data\ntest_df = pd.DataFrame(test_preprocessor.fit_transform(test_df), index = test_df.index, columns = test_features)\n\n#Register new users and questions\nusers_val, questions_val = reg_new_users_and_questions(test_df, users_df, questions_df)\n    \n#Make predictions\ntest_df = test_df.join(users_val, on = 'user_id')\ntest_df = test_df.join(questions_val, on = 'content_id')\npreds = model_1.predict(test_df[features])\n    \n#submit_predictions\ntest_df['answered_correctly'] = preds\nenv.predict(test_df.loc[(test_df['content_type_id'] == 0), ['row_id', 'answered_correctly']])\n\nlast_test_df = test_df\n\nfor (test_df, sample_prediction_df) in iter_test:\n    \n    #Get previous batch answers_correct\n    y = test_df['prior_group_answers_correct'].iloc[0,]\n    y = pd.Series([int(i) for i in y[1:-1].split(', ')], index = last_test_df.index)\n    \n    #Update ratings\n    #users_val, questions_val = update_ratings(last_test_df, y, preds, users_val, questions_val)\n    \n    #Preprocess data\n    test_df = pd.DataFrame(test_preprocessor.fit_transform(test_df), index = test_df.index, columns = test_features)\n\n    #Register new users and questions\n    users_val, questions_val = reg_new_users_and_questions(test_df, users_val, questions_val)\n    \n    #Make predictions\n    test_df = test_df.join(users_val, on = 'user_id')\n    test_df = test_df.join(questions_val, on = 'content_id')\n    preds = model_1.predict(test_df[features])\n    \n    #submit_predictions\n    test_df['answered_correctly'] = preds\n    env.predict(test_df.loc[test_df['content_type_id'] == 0, ['row_id', 'answered_correctly']])\n\n    last_test_df = test_df","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}