{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport random\nimport torch\nimport torch.nn as nn","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"cols_to_load = ['user_id','timestamp','content_id','prior_question_had_explanation','answered_correctly']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data = pd.read_pickle(\"../input/real-data-for-version1/out.pkl\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"correct = data[data.answered_correctly != -1].groupby([\"content_id\", 'answered_correctly'], as_index=False).size()\ncorrect = correct.pivot(index= \"content_id\", columns='answered_correctly', values='size')\ncorrect.columns = ['Wrong', 'Right']\ncorrect = correct.fillna(0)\ncorrect[['Wrong', 'Right']] = correct[['Wrong', 'Right']].astype(int)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"acu_id  = correct.Right/(correct.Wrong + correct.Right)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data = data[cols_to_load]","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import riiideducation\nenv = riiideducation.make_env()\niter_test = env.iter_test()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def clust_info(user_id,timestamp,data):  # get former sequence\n    # user_id is in data.user_id \n    cols_to_output = ['content_id','prior_question_had_explanation','answered_correctly']\n    user_re = data[data.user_id==user_id]\n    user_re = user_re[user_re.timestamp < timestamp]\n    user_re = user_re[cols_to_output]\n    return user_re","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def df_to_input(df):\n    return(torch.tensor(np.array(df))[None,:,:])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"content_num = 40000\ndevice = torch.device('cpu')\nclass Riiid(nn.Module):\n    def __init__(self, emb_con_size=16, emb_bin_size=8, hidden_size=32, middle_size=16, state_size=4, dropout=0.2):\n        self.hidden_size = hidden_size\n        self.emb_con_size = emb_con_size\n        self.emb_bin_size = emb_bin_size\n        self.middle_size = middle_size\n        self.state_size = state_size\n        super(Riiid, self).__init__()\n        self.Emb_content = nn.Embedding(content_num, self.emb_con_size)\n        self.Emb_ans = nn.Embedding(2, self.emb_bin_size)\n        self.Emb_explanation = nn.Embedding(2, self.emb_bin_size)\n        self.LSTM = nn.LSTM(input_size=self.emb_bin_size+self.emb_con_size, hidden_size=self.hidden_size,\n                            batch_first=True)\n        self.fc = nn.Linear(in_features=self.hidden_size+self.emb_con_size+self.emb_bin_size+self.state_size,\n                            out_features=self.middle_size)\n        self.decoder = nn.Linear(in_features=self.middle_size, out_features=1)\n        self.ln = nn.Linear(1, self.state_size)\n        self.dropout = nn.Dropout(dropout)\n        nn.init.xavier_uniform_(self.decoder.weight)\n\n    def forward(self, seq_data, seq_tar, seq_ans, length):\n        # input: seq + len\n        len_sorted, sorted_idx = length.sort(0, descending=True)\n        # content id and ans\n        seq_cat = torch.cat([seq_data[:, :, 0][:, :, None], seq_ans], dim=-1)\n        seq_sorted = seq_cat[sorted_idx.long().reshape(-1)]\n        emb_seq_con = self.Emb_content(seq_sorted[:, :, 0].to(device))\n        emb_seq_ans = self.Emb_ans(seq_sorted[:, :, 1].to(device))\n        emb_data_sorted = torch.cat([emb_seq_con, emb_seq_ans], dim=-1)\n        packed_seq = nn.utils.rnn.pack_padded_sequence(emb_data_sorted, len_sorted.long().reshape(-1).cpu().data.numpy(),\n                                                       batch_first=True)\n\n        rnn_out, hid = self.LSTM(packed_seq)  # hid is the knowledge state\n        # rnn_out, length_unpacked = nn.utils.rnn.pad_packed_sequence(rnn_out, batch_first=True)\n        _, origin_index = sorted_idx.sort(0, descending=False)\n        # rnn_out = rnn_out[origin_index.long()][:, 0, 0, :, :].contiguous()\n        emb_seq_tar_q = self.Emb_content(seq_tar[:, :, 0])  # emb q info\n        emb_seq_tar_e = self.Emb_explanation(seq_tar[:, :, 1])  # emb explanation\n        q_state = torch.cat([emb_seq_tar_q, emb_seq_tar_e], -1)\n\n        u_state_in = torch.div(torch.sum(seq_ans, 1).float(), length[:, :, 0].float()) # could be put in data process\n        u_state = self.ln(u_state_in)\n\n        fc_in = hid[0]\n        fc_in = fc_in[0][origin_index][:, 0, 0, :]\n        # fc_in = torch.zeros([rnn_out.shape[0], rnn_out.shape[2]])\n        # for i in range(len(length_unpacked)):\n        #     fc_in[i] = rnn_out[i, length_unpacked[i] - 1, :]\n        state = torch.cat([q_state[:, 0, :], fc_in.to(device), u_state], -1)\n        out = torch.sigmoid(self.decoder(self.fc(state.float())))\n        return out","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"net = Riiid()\nmodel = torch.load(\"../input/model-parameters/model.pickle\",map_location=torch.device('cpu'))\nnet.param = model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def convert_test(test_line):\n    out_0 = test_line.content_id\n    if test_line.prior_question_had_explanation:\n        out_1 = 1\n    else:\n        out_1 = 0\n    return(torch.tensor([[[out_0,out_1]]]))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def test_out(test):\n    re = list()\n    for i in range(len(test)):\n        tar = test.iloc[i]\n        if tar.user_id in data.user_id:\n            prior_seq = clust_info(tar.user_id,tar.timestamp,data) # 如果content未学习过，直接采用随机化的emb 可能会影响效果\n            temp = df_to_input(prior_seq)\n            \n            re += net(temp[:,:,:2],convert_test(tar),torch.abs(temp[:,:,2][:,:,None]),torch.tensor([[[temp.shape[1]]]]))[0].data.numpy().tolist()\n            \n        else: # user\n            if tar.content_id < len(acu_id):\n                re += [acu_id[tar.content_id]]\n            else:\n                re.append(0.5)\n        \n    return re","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"cols_to_load_ = ['user_id','timestamp','content_id','prior_question_had_explanation']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for (test_df, sample_prediction_df) in iter_test:\n    test_df=test_df[test_df['content_type_id'] == 0]\n    test_df.reset_index(drop=True)\n    re = test_out(test_df[cols_to_load_])\n    test_df['answered_correctly']=re\n    env.predict(test_df[['row_id', 'answered_correctly']])","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}