{"cells":[{"metadata":{},"cell_type":"markdown","source":"# このNotebookについて\n- このNotebookは、Riiidを解く前に知っておくとよいものをまとめたものです。\n- 必要と思ったものがあれば随時更新します(一部、作成中のところもありますがご了承ください)\n- 筆者は、英語が得意ではないため、誤り翻訳、誤解などが発生する可能性があります。"},{"metadata":{},"cell_type":"markdown","source":"# Riiidコンペについて\n\n## コンペ主催者\n- [RiiidLabs](https://riiidlabs.ai/solutions)\n    - AIを活用して、あらゆる業界の問題解決をする企業のようです。現在は、教育問題に取り組んでいるようだ。\n    - 以下の情報より、Riiidは、AIによって個人最適化されたTOEIC学習アプリを提供する韓国初スタートアップとのこと\n    - https://sunryse.co/app/startups/r_6WjOnZ6mV7JPbpY\n    \n## 知っておくと戦いやすくなる知識(のはず)\n\n- ここの項目に書くことは推測です。\n- [riiid](https://www.riiid.co/en/product)からリンクをたどると[TOEIC学習アプリ・santatoeic](https://santatoeic.jp/)にたどり着きます。\n- santatoeicは登録無料である程度、テストや講義を試すことができます。\n- ためした結果、実は、今回のコンペのデータ構成と、santatoeicを比較するとかなり類似しているように思えます。\n- 類似している箇所を気づいた限り挙げると以下のとおりです\n    - lectures.csvのpartの数が７つと、santatoeiと一致する\n    - questions.csvのpartは、TOEICテストの関連セクション\n    - santatoeicにも診断テスト、講義がある。\n    - santatoeicは、AIチューターシステムを採用している。\n- つまり、今回のコンペはsantatoeicと深く関係があるかもしれません。\n- よって、このコンペのデータ構成がイメージしづらいときは、santatoeicを使ってみるとイメージしやすくなります。\n    \n## 前提条件\n\n- これ以降の説明は、学生達がTOEIC学習アプリを使って診断テスト、講義を受けている場面を想定して記載します。\n\n\n## 主催者がコンペを開催する意図(目的)\n\n- (注意)以下に書く内容は、筆者の解釈です。\n- Riiid社は、学生のレベルに合わせたコンテンツ(質問、講義)を提供したい。\n- それを実現するため、ユーザの使用状況(問題回答状況、正解率など)から、最適なコンテンツを提供を目指している。\n- コンペのお題は、過去の正解状況などを元に、質問に答えられるかを予測します。\n- 予測の目的は、AIチューターシステムが、学生のレベルに合わせたコンテンツを作るためと推測されます。\n\n\n\n## コンペの概要\n\n- Riiid! Answer Correctness Prediction\n    - 生徒は、次の問題に答えられるか！AIの力で予測してください\n- Track knowledge states of 1M+ students in the wild\n    - EdNet上の100万人以上の学生の知識状態(問題回答状況、正解率など)を追跡する\n\n## コンペが開催される背景\n\n現在、2億6000万人の子供たちが学校に通っていません。\nこれらの若い学生の半数以上は、最低限の読書と数学の基準を満たしていませんでした。\nCOVID-19のこともあり 現在の教育システムを再構築する必要がある。\n\n## コンペでやるべきこと\n\n生徒が将来の相互作用でどのように行動するかを正確に予測することです。 \nRiiidのEdNetデータを使用して、機械学習スキルを活用して予測します。\n\nそして、時間の経過に伴う学生の知識のモデリングである「Knowledge Tracing(知識追跡)」のアルゴリズムを作成することです。\n\n\n受賞(優勝？)チームは、2021年2月に開催されるAI教育に関するAAAI-2021ワークショップ（AIによるCOVID後の教育の想像）でモデルを発表するよう招待されます。"},{"metadata":{},"cell_type":"markdown","source":"# コンペで使用するデータ"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\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 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":{},"cell_type":"markdown","source":"## train.csv(訓練データ)"},{"metadata":{"trusted":true},"cell_type":"code","source":"#データ多いため100万行まで読み込んで見る\ntrain_df = pd.read_csv(\"/kaggle/input/riiid-test-answer-prediction/train.csv\",nrows=10**6 )\ntrain_df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#uniquの数を出そう\ntrain_df.nunique()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#uniqueの割合を確認\ntrain_df['content_type_id'].value_counts().to_dict()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#1ユーザーあたりのレコード数を出してみる\n#多い人だと1万件のレコードが存在するようだ\ntrain_df['user_id'].value_counts(sort=True,ascending=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df['task_container_id'].value_counts(sort=True,ascending=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df['prior_question_had_explanation'].value_counts(sort=True,ascending=False).to_dict()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#content_idとtask_container_idの関係がよくわからないので調べてみる\n#content_idとtask_container_idがイコール関係は100万行中168件のみ、少なくとも\n#少なくともcontent_idとtask_container_idが同じ意味でないことがわかる\ntrain_df[(train_df[\"content_id\"] ==train_df['task_container_id'])]\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#ためしにcontent_id==1のデータに絞って出力してみよう\n#content_id=1は、何種類かのtask_container_idに属していることがわかる\ntrain_df[train_df[\"content_id\"] ==1]\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#さらにtask_container_id==２０のデータに絞って出力してみよう\n#task_container_idは、複数のcontent_idを持つことがわかった\ntrain_df[train_df[\"task_container_id\"] ==20].sort_values('user_id')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#一人のユーザは、どのようなデータを持つのか確認しよう\n#まず、レコード数(=質問の数が多い)が多いユーザを特定する\n#とりあえずuser_id=1283420あたりをサンプルとする(id=7171715は、極端に値が大きい。異常値？)\nuser_df = train_df[train_df.answered_correctly != -1].groupby('user_id').agg({'answered_correctly': ['count', 'mean']}).reset_index()\nuser_df.columns = ['user_id', 'user_questions', 'user_mean']\nuser_df.sort_values('user_questions')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#説明にある通り、１つのtask_container_idは、３つのcontent_idを持つことがわかった\ntrain_df[train_df[\"user_id\"] ==1283420]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#CSV作成用に読み込み\ntrain_df_csv = pd.read_csv(\"/kaggle/input/riiid-test-answer-prediction/train.csv\",nrows=1000)\ntrain_df_csv.to_csv(\"train_df_1000.csv\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## カラムの説明\n### row_id(int64)\n>ID code for the row.\n\n行に対するID\n\n### timestamp(int64)\n> the time in milliseconds between this user interaction and the first event completion from that user.\n\nこのユーザーインタラクション(ユーザの新規登録)から、該当レコードのイベント完了までのミリ秒単位の時間。\n訓練データの１つのuser_idに着目すると、timestampがレコード発生ごとに増えていくのがわかるかと思います。\n\n\n### user_id: (int32) \n> ID code for the user.\n\nユーザーのIDコード。\n\n### content_id: (int16) \n> ID code for the user interaction\n\nユーザーインタラクションのIDコード。\n「インタラクション」だと分かりづらい表現だから、単にコンテンツIDで良いと思う。\n\n\n\n### content_type_id: (int8) \n> 0 if the event was a question being posed to the user, 1 if the event was the user watching a lecture.\n\nイベントがユーザーに提示された質問の場合は0、イベントが講義を見ているユーザーの場合は1。\n100万件のデータで比較すると、件数は以下のようになっている。\n{0: 980093, 1: 19907}\n\n### task_container_id: (int16) \n> Id code for the batch of questions or lectures. For example, a user might see three questions in a row before seeing the explanations for any of them. Those three would all share a task_container_id.\n\n質問または講義のバッチのIDコード。\nたとえば、ユーザーは、いずれかの説明を表示する前に、3つの質問を連続して表示する場合があります。\nこれら3つはすべてtask_container_idを共有します。\n\n### user_answer: (int8) \n> the user's answer to the question, if any. Read -1 as null, for lectures.\n\n質問に対するユーザーの回答(数字で答えるようだ)。講義の場合は、-1を「null」として読み取ります。\n※質問した回数ではない(筆者は最初、質問の回数のことだと思っていた。)\n\n### answered_correctly: (int8) \n> if the user responded correctly. Read -1 as null, for lectures.\n\nユーザーが正しく応答した場合。講義の場合は、-1をnullとして読み取ります。\n\n### prior_question_elapsed_time: (float32) \n> The average time in milliseconds it took a user to answer each question in the previous question bundle, ignoring any lectures in between. Is null for a user's first question bundle or lecture. Note that the time is the average time a user took to solve each question in the previous bundle.\n\nユーザーが前の質問バンドルの各質問に回答するのにかかった平均時間（ミリ秒単位）。\nその間の講義は無視されます。ユーザーの最初の質問バンドルまたは講義ではnullです。\n時間は、ユーザーが前のバンドルの各質問を解決するのにかかった平均時間であることに注意してください。\n\n### prior_question_had_explanation: (bool) \n> Whether or not the user saw an explanation and the correct response(s) after answering the previous question bundle, ignoring any lectures in between. The value is shared across a single question bundle, and is null for a user's first question bundle or lecture. Typically the first several questions a user sees were part of an onboarding diagnostic test where they did not get any feedback.\n\n\nユーザーが前の質問バンドルに回答した後、説明と正しい回答を見たかどうか。その間の講義は無視されます。\n値は単一の質問バンドル間で共有され、ユーザーの最初の質問バンドルまたは講義ではnullになります。通常、ユーザーに表示される最初のいくつかの質問は、フィードバックが得られなかったオンボーディング診断テストの一部でした。\n\n要するに、前回、質問に回答した後に解説をみたかどうか。最初の質問のときは、(当然のことながら)解説を見れないからnullになる。\n実際の値は以下の通り。<br>\n{True: 889887, False: 106297}\n"},{"metadata":{},"cell_type":"markdown","source":"## questions.csv(質問データ)"},{"metadata":{"trusted":true},"cell_type":"code","source":"questions_df = pd.read_csv(\"/kaggle/input/riiid-test-answer-prediction/questions.csv\")\nquestions_df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#uniquの数を出そう\nquestions_df.nunique()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"questions_df['bundle_id'].value_counts(sort=True,ascending=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#questions.csvを見ていると、question_idとbundle_idは、同じ値になっているように見える\n#本当かどうか確認する\n#確認した結果、同一bundle_idに、いくつかのquestion_idが紐づくことがわかる。\nquestions_df[questions_df[\"question_id\"] != questions_df[\"bundle_id\"]]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#ためしに bundle_id=7795のデータを見てみよう\n#大問題=bundle_id, 小問題=question_idと考えて良さそうだ\n#partが全て一致、tagsもほぼ一致していることがわかる\nquestions_df[questions_df[\"bundle_id\"] == 7795]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### question_id: \n> foreign key for the train/test content_id column, when the content type is question (0).\n\nコンテンツタイプが質問ならば0、question_idは、train / testの「content_id」列の外部キー。\n\n\n### bundle_id:\n> code for which questions are served together.\n\n質問が一緒に提供されるコード。\n大問題=bundle_id, 小問題=question_idというイメージ。\n\n### correct_answer:\n> the answer to the question. Can be compared with the train user_answer column to check if the user was right.\n\n質問への回答。 train.csvの「user_answer」列と比較して、ユーザーが正しいかどうかを確認できます\n\n### part: \n> the relevant section of the TOEIC test.\n\nTOEICテストの関連セクション。\n\n### tags: \n> one or more detailed tag codes for the question. The meaning of the tags will not be provided, but these codes are sufficient for clustering the questions together.\n\n質問の1つ以上の詳細なタグコード。タグの意味は提供されませんが、これらのコードは質問をまとめるのに十分です。\n"},{"metadata":{},"cell_type":"markdown","source":"# lectures.csv(講義のメタデータ)\n\n\nユーザーが教育を進めるときに視聴する講義のメタデータ。"},{"metadata":{"trusted":true},"cell_type":"code","source":"lectures_df = pd.read_csv(\"/kaggle/input/riiid-test-answer-prediction/lectures.csv\")\nlectures_df","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### lecture_id: \n> foreign key for the train/test content_id column, when the content type is lecture (1).\n\nコンテンツタイプが講義（1）の場合、train / testcontent_id列の外部キー。\n\n### part:\n>  top level category code for the lecture.\n\n講義のトップレベルのカテゴリコード。\n\n### tag:\n>  one tag codes for the lecture. The meaning of the tags will not be provided, but these codes are sufficient for clustering the lectures together.\n\n講義用の1つのタグコード。タグの意味は提供されませんが、これらのコードは講義をまとめるのに十分です。\n\n### type_of:\n>  brief description of the core purpose of the lecture\n\n講義の主な目的の簡単な説明\n"},{"metadata":{},"cell_type":"markdown","source":"## example_test_rows.csv(テストセットデータ)\n\n時系列APIによって配信されるテストセットデータの3つのサンプルグループ。形式はtrain.csvとほぼ同じです。 AIチューターがいつでも実際に利用できる情報を反映する、2つの異なる列がありますが、一度に1人のユーザーの情報を厳密に表示するのではなく、APIパフォーマンスのためにユーザーインタラクションをグループ化します。一部のユーザーは、訓練データに表示されていない非表示のテストセットに表示され、Webサイトへの新着のモデリングにすばやく適応するという課題をエミュレートします。\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df = pd.read_csv(\"/kaggle/input/riiid-test-answer-prediction/example_test.csv\")\ntest_df","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### prior_group_responses (string)\n>provides all of the user_answer entries for previous group in a string representation of a list in the first row of the group. All other rows in each group are null. If you are using Python, you will likely want to call eval on the non-null rows. Some rows may be null, or empty lists.\n\nprior_group_responses（string）は、前のグループのすべてのuser_answerエントリを、グループの最初の行のリストの文字列表現で提供します。各グループの他のすべての行はnullです。 Pythonを使用している場合は、null以外の行でevalを呼び出すことをお勧めします。一部の行はnullまたは空のリストである可能性があります。\n\n\n### prior_group_answers_correct (string)\n> provides all the answered_correctly field for previous group, with the same format and caveats as prior_group_responses. Some rows may be null, or empty lists.\n\nprior_group_answers_correct（string）は、prior_group_responsesと同じ形式と警告で、前のグループのすべてのanswered_correctlyフィールドを提供します。一部の行はnullまたは空のリストである可能性があります。"},{"metadata":{},"cell_type":"markdown","source":"## example_sample_submission.csv(提出サンプルファイル)"},{"metadata":{"trusted":true},"cell_type":"code","source":"submission_df = pd.read_csv(\"/kaggle/input/riiid-test-answer-prediction/example_sample_submission.csv\")\nsubmission_df","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 時系列APIの詳細(Time-series API Details)"},{"metadata":{},"cell_type":"markdown","source":"> Refer to the starter notebook for an example of how to complete a submission. The time-series API has changed somewhat from previous competitions!\n\n提出を完了する方法の例については、[スターターノートブック](https://www.kaggle.com/sohier/competition-api-detailed-introduction)を参照してください。時系列APIは、以前のコンテストから多少変更されました。\n\n\n> You should not try to submit anything for the rows that contain lectures.\n\n講義を含む行には何も送信しようとしないでください。\n\n\n> The API provides user interactions groups in the order in which they occurred. Each group will contain interactions from many different users, but no more than one task_container_id of questions from any single user. Each group has between 1 and 1000 users.\n\nAPIは、ユーザーインタラクショングループを発生順に提供します。各グループには、多くの異なるユーザーからのインタラクションが含まれますが、単一のユーザーからの質問のtask_container_idは1つだけです。各グループには1〜1000人のユーザーがいます。\n\n\n> Expect to see roughly 2.5 million questions in the hidden test set.\n\n非表示のテストセットで約250万の質問が表示されると予想されます。\n\n\n> The API will load up to 1 GB of the test set data in memory after initialization. The initialization step (env.iter_test()) will require meaningfully more memory than that; we recommend you do not load your model until after making that call. The API will also consume roughly 15 minutes of runtime for loading and serving the data, but will also obfuscate the true runtime for all submissions.\n\nAPIは、初期化後に最大1GBのテストセットデータをメモリにロードします。初期化ステップ（env.iter_test（））は、それよりも意味のある量のメモリを必要とします。その呼び出しを行うまで、モデルをロードしないことをお勧めします。 APIは、データのロードと提供に約15分のランタイムも消費しますが、すべての送信の実際のランタイムを難読化します。\n\n> The API loads the data using the types specified above (int32 for user_id, int8 for content_type_id, etc).\n\nAPIは、上記で指定されたタイプ（user_idの場合はint32、content_type_idの場合はint8など）を使用してデータをロードします。\n\n"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","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}