{"cells":[{"metadata":{},"cell_type":"markdown","source":"# **Hello there!**\n\nLet me start by stating that i am new to kaggle and data science in general so any mistakes i make or if there are any suggestions to be given, please feel free to point that out in the comments section below.\n\nWhile reading and going through this competition and its notebooks i came across this particular notebook called [0-780-unoptimized-lgbm-interesting-features](https://www.kaggle.com/zyy2016/0-780-unoptimized-lgbm-interesting-features). Here the author talks about using **Trueskill** features. This peaked my interest and so i tried to explore it and am making this notebook for other beginners like me to undertsand this concept. If you like the above notebook please do drop an upvote as it helps the author reach out to more people and spread his work and learn more.\n\nI don't know how much this'll help in the competition prediction or scorewise, but this is just an interesting concept that i wanted to explore more of. So here goes nothing..."},{"metadata":{},"cell_type":"markdown","source":"# So what exactly is TrueSkill?\n\nAccording to [TrueSkill.org](https://trueskill.org/)\n\n\"TrueSkill is a rating system among game players. It was developed by Microsoft Research and has been used on Xbox LIVE for ranking and matchmaking service. This system quantifies players’ TRUE skill points by the Bayesian inference algorithm. It also works well with any type of match rule including N:N team game or free-for-all.\"\n\nIn simple words, if you are a participant in a competition, then you will be recognized by a number. That number is your TrueSkill rating. When two participants clash, depending on which participant wins, that number gets updated. If participant A wins against Participant B then the rating of A shall increase and B shall decrease based on certain calculations."},{"metadata":{},"cell_type":"markdown","source":"# So how does this relate to Riid!\n\nThink of TOEIC test as a competition not as a test. So you treat every **user_id** as a participant and every **content_id** as a unique participant as well. Everytime a user answers a question correctly, the rating for the user_id **increases** and the rating for the content_id **decreases** . The reverse of this happens when the user answers a question incorrectly."},{"metadata":{"trusted":true},"cell_type":"code","source":"import datatable as dt\nimport pandas as pd\nimport numpy as np\nfrom trueskill import Rating, quality_1vs1, rate_1vs1\nimport math\nimport trueskill","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data_types_dict = {\n    'timestamp': 'int64',\n    'user_id': 'int32', \n    'content_id': 'int16', \n    'content_type_id':'int8', \n    'task_container_id': 'int16',\n    'answered_correctly': 'int8', \n    'prior_question_elapsed_time': 'float32', \n    'prior_question_had_explanation': 'bool'\n}\ntarget = 'answered_correctly'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#loading the dataset using datatable\ntrain = dt.fread('../input/riiid-test-answer-prediction/train.csv', columns=set(data_types_dict.keys())).to_pandas()\nprint(\"Data Loaded\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train = train[train[target] != -1].reset_index(drop=True)\nprint(\"Lecture columns removed\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train = train.astype(data_types_dict)\nprint(\"Basic Pre Processing Done\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train = train.groupby('user_id').tail(4)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"users = np.unique(train[\"user_id\"])\nquestions = np.unique(train[\"content_id\"])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"rating_users = []\nfor user in users:\n    rating_object = Rating()\n    rating_users.append(rating_object)\n\nrating_questions = []\nfor question in questions:\n    rating_object = Rating()\n    rating_questions.append(rating_object)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dict_users = dict(zip(users,rating_users))\ndict_questions = dict(zip(questions,rating_questions))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"answers = train[\"answered_correctly\"].values\nu_temp = train[\"user_id\"].values\nq_temp = train[\"content_id\"].values","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def win_probability(team1, team2):\n    delta_mu = team1.mu - team2.mu\n    sum_sigma = sum([team1.sigma ** 2, team2.sigma ** 2])\n    size = 2\n    denom = math.sqrt(size * (0.05 * 0.05) + sum_sigma)\n    ts = trueskill.global_env()\n    return ts.cdf(delta_mu / denom)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Above function has been taken from the notebook [0-780-unoptimized-lgbm-interesting-features](https://www.kaggle.com/zyy2016/0-780-unoptimized-lgbm-interesting-features). Do consider dropping an upvote."},{"metadata":{"trusted":true},"cell_type":"code","source":"count = 0\nwinning_probability = []\nprint(\"Creating Feature\")\nprint(\"Running this will take about 10 mins. Grab a chai :)\")\nfor user_id,content_id,answer in zip(u_temp,q_temp,answers):\n    count = count + 1\n    old_user_rating = dict_users[user_id]\n    old_question_rating = dict_questions[content_id]\n    prob = win_probability(old_user_rating,old_question_rating)\n    winning_probability.append(prob)\n    if answer == 1:\n        new_user_rating,new_question_rating = rate_1vs1(old_user_rating,old_question_rating)\n    if answer == 0:\n        new_question_rating,new_user_rating = rate_1vs1(old_question_rating,old_user_rating)\n    dict_users[user_id] = new_user_rating\n    dict_questions[content_id] = new_question_rating\n    if count%1000000 == 0:\n        print((count/1000000),\"million rows done\" )","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train[\"correct_prob\"] = winning_probability","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true},"cell_type":"code","source":"train.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Currently the most amount of time is used up on updating the dictionaries, which is why i haven't done it for the entire dataset. If you have a better way of updating them do please drop it in the comments. To avoid running the code again and again for the entire dataset, you could run this code and save the csv file to your working directory for further usage.\nIf you liked the kernel, do drop an upvote on it. As stated before any comments and suggestions are more than welcome."}],"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}