Kaggle competition: Riiid Answer Correctness Prediction
<SOS> metric: AUC Kaggle data source: riiid-answer-correctness-prediction<predict_on_test>
import pandas as pd
import numpy as np
import gc
from sklearn.metrics import roc_auc_score
from collections import defaultdict
from tqdm.notebook import tqdm
import lightgbm as lgb
import riiideducation
import matplotlib.pyplot as plt
import seaborn as sns
import psutil
import random
import os
Y_val2_predict= model2.predict(X_val2)
 print(confusion_matrix(Y_val2,Y_val2_predict))<normalization>
SEED = 123
def seed_everything(seed):
random.seed(seed)
 np.random.seed(seed)
 os.environ['PYTHONHASHSEED'] = str(seed)
 seed_everything(SEED )
scaler=MinMaxScaler()
minmax_scaled_features=scaler.fit_transform(X_trainval)
 X_trainval_3=pd.DataFrame(minmax_scaled_features,index=X_trainval.index,columns=X_trainval.columns)
 X_trainval_3.head() 
<split>
def add_features(df, answered_correctly_u_count, answered_correctly_u_sum, elapsed_time_u_sum, explanation_u_sum, timestamp_u, timestamp_u_incorrect, answered_correctly_q_count, answered_correctly_q_sum, elapsed_time_q_sum, explanation_q_sum, answered_correctly_uq, update = True):
answered_correctly_u_avg = np.zeros(len(df), dtype = np.float32)
 elapsed_time_u_avg = np.zeros(len(df), dtype = np.float32)
 explanation_u_avg = np.zeros(len(df), dtype = np.float32)
 timestamp_u_recency_1 = np.zeros(len(df), dtype = np.float32)
 timestamp_u_recency_2 = np.zeros(len(df), dtype = np.float32)
 timestamp_u_recency_3 = np.zeros(len(df), dtype = np.float32)
 timestamp_u_incorrect_recency = np.zeros(len(df), dtype = np.float32)
 answered_correctly_q_avg = np.zeros(len(df), dtype = np.float32)
 elapsed_time_q_avg = np.zeros(len(df), dtype = np.float32)
 explanation_q_avg = np.zeros(len(df), dtype = np.float32)
 answered_correctly_uq_count = np.zeros(len(df), dtype = np.int32)
 for num, row in enumerate(df[['user_id', 'answered_correctly', 'content_id', 'prior_question_elapsed_time', 'prior_question_had_explanation', 'timestamp']].values):
if answered_correctly_u_count[row[0]] != 0:
answered_correctly_u_avg[num] = answered_correctly_u_sum[row[0]] / answered_correctly_u_count[row[0]]
elapsed_time_u_avg[num] = elapsed_time_u_sum[row[0]] / answered_correctly_u_count[row[0]]
explanation_u_avg[num] = explanation_u_sum[row[0]] / answered_correctly_u_count[row[0]]
else:
answered_correctly_u_avg[num] = np.nan
elapsed_time_u_avg[num] = np.nan
explanation_u_avg[num] = np.nan
if len(timestamp_u[row[0]])== 0:
timestamp_u_recency_1[num] = np.nan
timestamp_u_recency_2[num] = np.nan
timestamp_u_recency_3[num] = np.nan
elif len(timestamp_u[row[0]])== 1:
timestamp_u_recency_1[num] = row[5] - timestamp_u[row[0]][0]
timestamp_u_recency_2[num] = np.nan
timestamp_u_recency_3[num] = np.nan
elif len(timestamp_u[row[0]])== 2:
timestamp_u_recency_1[num] = row[5] - timestamp_u[row[0]][1]
timestamp_u_recency_2[num] = row[5] - timestamp_u[row[0]][0]
timestamp_u_recency_3[num] = np.nan
elif len(timestamp_u[row[0]])== 3:
timestamp_u_recency_1[num] = row[5] - timestamp_u[row[0]][2]
timestamp_u_recency_2[num] = row[5] - timestamp_u[row[0]][1]
timestamp_u_recency_3[num] = row[5] - timestamp_u[row[0]][0]
if len(timestamp_u_incorrect[row[0]])== 0:
timestamp_u_incorrect_recency[num] = np.nan
else:
timestamp_u_incorrect_recency[num] = row[5] - timestamp_u_incorrect[row[0]][0]
if answered_correctly_q_count[row[2]] != 0:
answered_correctly_q_avg[num] = answered_correctly_q_sum[row[2]] / answered_correctly_q_count[row[2]]
elapsed_time_q_avg[num] = elapsed_time_q_sum[row[2]] / answered_correctly_q_count[row[2]]
explanation_q_avg[num] = explanation_q_sum[row[2]] / answered_correctly_q_count[row[2]]
else:
answered_correctly_q_avg[num] = np.nan
elapsed_time_q_avg[num] = np.nan
explanation_q_avg[num] = np.nan
answered_correctly_uq_count[num] = answered_correctly_uq[row[0]][row[2]]
answered_correctly_u_count[row[0]] += 1
elapsed_time_u_sum[row[0]] += row[3]
explanation_u_sum[row[0]] += int(row[4])
 if len(timestamp_u[row[0]])== 3:
timestamp_u[row[0]].pop(0)
 timestamp_u[row[0]].append(row[5])
 else:
timestamp_u[row[0]].append(row[5])
 answered_correctly_q_count[row[2]] += 1
elapsed_time_q_sum[row[2]] += row[3]
explanation_q_sum[row[2]] += int(row[4])
 answered_correctly_uq[row[0]][row[2]] += 1
if update:
answered_correctly_u_sum[row[0]] += row[1]
if row[1] == 0:
if len(timestamp_u_incorrect[row[0]])== 1:
timestamp_u_incorrect[row[0]].pop(0)
 timestamp_u_incorrect[row[0]].append(row[5])
 else:
timestamp_u_incorrect[row[0]].append(row[5])
 answered_correctly_q_sum[row[2]] += row[1]
user_df = pd.DataFrame({'answered_correctly_u_avg': answered_correctly_u_avg, 'elapsed_time_u_avg': elapsed_time_u_avg, 'explanation_u_avg': explanation_u_avg,
'answered_correctly_q_avg': answered_correctly_q_avg, 'elapsed_time_q_avg': elapsed_time_q_avg, 'explanation_q_avg': explanation_q_avg,
'answered_correctly_uq_count': answered_correctly_uq_count, 'timestamp_u_recency_1': timestamp_u_recency_1, 'timestamp_u_recency_2': timestamp_u_recency_2,
'timestamp_u_recency_3': timestamp_u_recency_3, 'timestamp_u_incorrect_recency': timestamp_u_incorrect_recency})
 df = pd.concat([df, user_df], axis = 1)
 return df
def update_features(df, answered_correctly_u_sum, answered_correctly_q_sum, timestamp_u_incorrect):
for row in df[['user_id', 'answered_correctly', 'content_id', 'content_type_id', 'timestamp']].values:
if row[3] == 0:
answered_correctly_u_sum[row[0]] += row[1]
if row[1] == 0:
if len(timestamp_u_incorrect[row[0]])== 1:
timestamp_u_incorrect[row[0]].pop(0)
 timestamp_u_incorrect[row[0]].append(row[4])
 else:
timestamp_u_incorrect[row[0]].append(row[4])
 answered_correctly_q_sum[row[2]] += row[1]
return
X_train3,X_val3,Y_train3,Y_val3=train_test_split(X_trainval_3,Y_trainval,test_size=0.2,random_state=42)
 print("X_train shape: ",X_train3.shape)
 print("X_val shape: ",X_val3.shape)
 print("Y_train shape: ",Y_train3.shape)
 print("Y_val shape: ",Y_val3.shape )<train_model>
def read_and_preprocess(feature_engineering = False):
train_pickle = '.. /input/riiid-cross-validation-files/cv1_train.pickle'
valid_pickle = '.. /input/riiid-cross-validation-files/cv1_valid.pickle'
question_file = '.. /input/riiid-test-answer-prediction/questions.csv'
feld_needed = ['timestamp', 'user_id', 'answered_correctly', 'content_id', 'content_type_id', 'prior_question_elapsed_time', 'prior_question_had_explanation']
train = pd.read_pickle(train_pickle)[feld_needed]
valid = pd.read_pickle(valid_pickle)[feld_needed]
MAX_SEQ = 100
skills = train["content_id"][train.content_type_id == False].unique()
n_skill = len(skills)
 print("number skills", len(skills))
group = train[['user_id', 'content_id', 'answered_correctly']][train.content_type_id == False].groupby('user_id' ).apply(lambda r:(
 r['content_id'].values,
r['answered_correctly'].values))
for user_id in group.index:
q, qa = group[user_id]
if len(q)>MAX_SEQ:
group[user_id] =(q[-MAX_SEQ:],qa[-MAX_SEQ:])
 pickle.dump(group, open("group.pkl", "wb"))
del group
gc.collect()
train=train.append(valid, ignore_index = False)
 del(valid)
 gc.collect()
train = train.groupby('user_id' ).tail(320 ).reset_index(drop=True)
 valid = train.groupby('user_id' ).tail(16)
 train.drop(valid.index, inplace=True)
 gc.collect()
train = train.loc[train.content_type_id == False].reset_index(drop = True)
 valid = valid.loc[valid.content_type_id == False].reset_index(drop = True)
 if feature_engineering:
train = train.iloc[-34400000:]
train['prior_question_had_explanation'] = train.prior_question_had_explanation.fillna(False ).astype('int8')
 valid['prior_question_had_explanation'] = valid.prior_question_had_explanation.fillna(False ).astype('int8')
 prior_question_elapsed_time_mean = train['prior_question_elapsed_time'].dropna().mean()
train['prior_question_elapsed_time'].fillna(prior_question_elapsed_time_mean, inplace = True)
 valid['prior_question_elapsed_time'].fillna(prior_question_elapsed_time_mean, inplace = True)
 questions_df = pd.read_csv(question_file)
 questions_df['part'] = questions_df['part'].astype(np.int32)
 questions_df['bundle_id'] = questions_df['bundle_id'].astype(np.int32)
 train = pd.merge(train, questions_df[['question_id', 'part']], left_on = 'content_id', right_on = 'question_id', how = 'left')
 valid = pd.merge(valid, questions_df[['question_id', 'part']], left_on = 'content_id', right_on = 'question_id', how = 'left')
 answered_correctly_u_count = defaultdict(int)
 answered_correctly_u_sum = defaultdict(int)
 elapsed_time_u_sum = defaultdict(int)
 explanation_u_sum = defaultdict(int)
 timestamp_u = defaultdict(list)
 timestamp_u_incorrect = defaultdict(list)
 answered_correctly_q_count = defaultdict(int)
 answered_correctly_q_sum = defaultdict(int)
 elapsed_time_q_sum = defaultdict(int)
 explanation_q_sum = defaultdict(int)
 answered_correctly_uq = defaultdict(lambda: defaultdict(int))
print('User feature calculation started...')
 print('
')
 train = add_features(train, answered_correctly_u_count, answered_correctly_u_sum, elapsed_time_u_sum, explanation_u_sum, timestamp_u, timestamp_u_incorrect, answered_correctly_q_count, answered_correctly_q_sum, elapsed_time_q_sum, explanation_q_sum, answered_correctly_uq)
 valid = add_features(valid, answered_correctly_u_count, answered_correctly_u_sum, elapsed_time_u_sum, explanation_u_sum, timestamp_u, timestamp_u_incorrect, answered_correctly_q_count, answered_correctly_q_sum, elapsed_time_q_sum, explanation_q_sum, answered_correctly_uq)
 gc.collect()
print('User feature calculation completed...')
 print('
')
 features_dicts = {
'answered_correctly_u_count': answered_correctly_u_count,
'answered_correctly_u_sum': answered_correctly_u_sum,
'elapsed_time_u_sum': elapsed_time_u_sum,
'explanation_u_sum': explanation_u_sum,
'answered_correctly_q_count': answered_correctly_q_count,
'answered_correctly_q_sum': answered_correctly_q_sum,
'elapsed_time_q_sum': elapsed_time_q_sum,
'explanation_q_sum': explanation_q_sum,
'answered_correctly_uq': answered_correctly_uq,
'timestamp_u': timestamp_u,
'timestamp_u_incorrect': timestamp_u_incorrect
}
return train, valid, questions_df, prior_question_elapsed_time_mean, features_dicts, MAX_SEQ ,n_skill,skills
model3=LogisticRegression()
model3.fit(X_train3,Y_train3)
 print("train set Accuracy: ",model3.score(X_train3,Y_train3))
print("test set Accuracy: ",model3.score(X_val3,Y_val3))<predict_on_test>
train, valid, questions_df, prior_question_elapsed_time_mean, features_dicts, MAX_SEQ ,n_skill,skills = read_and_preprocess(feature_engineering = True )
Y_val3_predict= model3.predict(X_val3)
 print(confusion_matrix(Y_val3,Y_val3_predict))<train_model>
def train_and_evaluate(train, valid, feature_engineering = False):
clfs = list()
num=1
TARGET = 'answered_correctly'
FEATURES = [
'prior_question_elapsed_time',
'prior_question_had_explanation',
'part',
'answered_correctly_u_avg',
'elapsed_time_u_avg',
'explanation_u_avg',
'answered_correctly_q_avg',
'elapsed_time_q_avg',
'explanation_q_avg',
'answered_correctly_uq_count',
'timestamp_u_recency_1',
'timestamp_u_recency_2',
'timestamp_u_recency_3',
'timestamp_u_incorrect_recency'
]
gc.collect()
print(f'Traning with {train.shape[0]} rows and {len(FEATURES)} features')
 drop_cols = list(set(train.columns)- set(FEATURES))
y_train = train[TARGET]
y_val = valid[TARGET]
train.drop(drop_cols, axis = 1, inplace = True)
 valid.drop(drop_cols, axis = 1, inplace = True)
 gc.collect()
for i in range(0,num):
lgb_train = lgb.Dataset(train[FEATURES], y_train)
 lgb_valid = lgb.Dataset(valid[FEATURES], y_val)
 del train, y_train
gc.collect()
params= {'objective': 'binary',
'metric': 'auc',
'verbosity': -1,
'boosting_type': 'gbdt',
'feature_pre_filter': False,
'learning_rate': 0.05,
'lambda_l1': 0.0003344679079114925,
'lambda_l2': 1.9095994876812776,
'num_leaves': 433,
'max_bin': 511,
'feature_fraction': 1.0,
'bagging_fraction': 1.0,
'bagging_freq': 0,
'min_child_samples': 20
}
paramsf = {'objective': 'binary',
'seed': SEED,
'metric': 'auc',
'num_leaves': 433,
'learning_rate': 0.05,
'feature_fraction': 0.75,
'bagging_freq': 10,
'bagging_fraction': 0.80
}
model = lgb.train(
 params = params,
train_set = lgb_train,
num_boost_round = 10000,
valid_sets = [lgb_train, lgb_valid],
early_stopping_rounds = 10,
verbose_eval = 50 
)
 clfs.append(model)
 print('Our Roc Auc score for the validation data is:', roc_auc_score(y_val, model.predict(valid[FEATURES])))
 feature_importance = model.feature_importance()
feature_importance = pd.DataFrame({'Features': FEATURES, 'Importance': feature_importance} ).sort_values('Importance', ascending = False)
 fig = plt.figure(figsize =(10, 10))
fig.suptitle('Feature Importance', fontsize = 20)
 plt.tick_params(axis = 'x', labelsize = 12)
 plt.tick_params(axis = 'y', labelsize = 12)
 plt.xlabel('Importance', fontsize = 15)
 plt.ylabel('Features', fontsize = 15)
 sns.barplot(x = feature_importance['Importance'], y = feature_importance['Features'], orient = 'h')
 plt.show()
return TARGET, FEATURES, model,clfs
model4=LinearSVC()
model4.fit(X_train1,Y_train1)
 print("train set Accuracy: ",model4.score(X_train1,Y_train1))
print("test set Accuracy: ",model4.score(X_val1,Y_val1))<predict_on_test>
TARGET, FEATURES, model,clfs = train_and_evaluate(train, valid, feature_engineering = True )
Y_val4_predict= model4.predict(X_val1)
 print(confusion_matrix(Y_val1,Y_val4_predict))<train_on_grid>
class FFN(nn.Module):
def __init__(self, state_size=200):
super(FFN, self ).__init__()
self.state_size = state_size
self.lr1 = nn.Linear(state_size, state_size)
 self.relu = nn.ReLU()
self.lr2 = nn.Linear(state_size, state_size)
 self.dropout = nn.Dropout(0.2)
 def forward(self, x):
x = self.lr1(x)
 x = self.relu(x)
 x = self.lr2(x)
 return self.dropout(x)
 def future_mask(seq_length):
future_mask = np.triu(np.ones(( seq_length, seq_length)) , k=1 ).astype('bool')
 return torch.from_numpy(future_mask)
 class SAKTModel(nn.Module):
def __init__(self, n_skill, max_seq=MAX_SEQ, embed_dim=128):
super(SAKTModel, self ).__init__()
self.n_skill = n_skill
self.embed_dim = embed_dim
self.embedding = nn.Embedding(2*n_skill+1, embed_dim)
 self.pos_embedding = nn.Embedding(max_seq-1, embed_dim)
 self.e_embedding = nn.Embedding(n_skill+1, embed_dim)
 self.multi_att = nn.MultiheadAttention(embed_dim=embed_dim, num_heads=8, dropout=0.2)
 self.dropout = nn.Dropout(0.2)
 self.layer_normal = nn.LayerNorm(embed_dim)
 self.ffn = FFN(embed_dim)
 self.pred = nn.Linear(embed_dim, 1)
 def forward(self, x, question_ids):
device = x.device
x = self.embedding(x)
 pos_id = torch.arange(x.size(1)).unsqueeze(0 ).to(device)
 pos_x = self.pos_embedding(pos_id)
 x = x + pos_x
e = self.e_embedding(question_ids)
 x = x.permute(1, 0, 2)
 e = e.permute(1, 0, 2)
 att_mask = future_mask(x.size(0)).to(device)
 att_output, att_weight = self.multi_att(e, x, x, attn_mask=att_mask)
 att_output = self.layer_normal(att_output + e)
 att_output = att_output.permute(1, 0, 2)
 x = self.ffn(att_output)
 x = self.layer_normal(x + att_output)
 x = self.pred(x)
 return x.squeeze(-1), att_weight
model5=LinearSVC()
model5.fit(X_train2,Y_train2)
 print("train set Accuracy: ",model5.score(X_train2,Y_train2))
print("test set Accuracy: ",model5.score(X_val2,Y_val2))<predict_on_test>
skills = joblib.load("/kaggle/input/riiid-sakt-model-dataset-public/skills.pkl.zip")
 n_skill = len(skills)
 group = joblib.load("/kaggle/input/riiid-sakt-model-dataset-public/group.pkl.zip" )
Y_val5_predict= model5.predict(X_val2)
 print(confusion_matrix(Y_val2,Y_val5_predict))<train_on_grid>
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
 SAKT_model = SAKTModel(n_skill, embed_dim=128)
 try:
SAKT_model.load_state_dict(torch.load("/kaggle/input/riiid-sakt-model-dataset-public/sakt_model.pt"))
except:
SAKT_model.load_state_dict(torch.load("/kaggle/input/riiid-sakt-model-dataset-public/sakt_model.pt", map_location='cpu'))
SAKT_model.to(device)
 SAKT_model.eval()
<train_model><EOS> 
def inference(TARGET, FEATURES, model, questions_df, prior_question_elapsed_time_mean, features_dicts):
answered_correctly_u_count = features_dicts['answered_correctly_u_count']
answered_correctly_u_sum = features_dicts['answered_correctly_u_sum']
elapsed_time_u_sum = features_dicts['elapsed_time_u_sum']
explanation_u_sum = features_dicts['explanation_u_sum']
answered_correctly_q_count = features_dicts['answered_correctly_q_count']
answered_correctly_q_sum = features_dicts['answered_correctly_q_sum']
elapsed_time_q_sum = features_dicts['elapsed_time_q_sum']
explanation_q_sum = features_dicts['explanation_q_sum']
answered_correctly_uq = features_dicts['answered_correctly_uq']
timestamp_u = features_dicts['timestamp_u']
timestamp_u_incorrect = features_dicts['timestamp_u_incorrect']
env = riiideducation.make_env()
iter_test = env.iter_test()
set_predict = env.predict
previous_test_df = None
for(test_df, sample_prediction_df)in iter_test:
if(previous_test_df is not None)&(psutil.virtual_memory().percent<90):
print(psutil.virtual_memory().percent)
 previous_test_df[TARGET] = eval(test_df["prior_group_answers_correct"].iloc[0])
 previous_test_df = previous_test_df[previous_test_df[TARGET] != -1].reset_index(drop=True)
 previous_test_df['prior_question_had_explanation'].fillna(False, inplace=True)
 previous_test_df.prior_question_had_explanation=previous_test_df.prior_question_had_explanation.astype('int8')
 prev_group = previous_test_df[['user_id', 'content_id', 'answered_correctly']].groupby('user_id' ).apply(lambda r:(
 r['content_id'].values,
r['answered_correctly'].values))
for prev_user_id in prev_group.index:
prev_group_content = prev_group[prev_user_id][0]
prev_group_ac = prev_group[prev_user_id][1]
if prev_user_id in group.index:
group[prev_user_id] =(np.append(group[prev_user_id][0],prev_group_content),
np.append(group[prev_user_id][1],prev_group_ac))
else:
group[prev_user_id] =(prev_group_content,prev_group_ac)
 if len(group[prev_user_id][0])>MAX_SEQ:
new_group_content = group[prev_user_id][0][-MAX_SEQ:]
new_group_ac = group[prev_user_id][1][-MAX_SEQ:]
group[prev_user_id] =(new_group_content,new_group_ac)
 update_features(previous_test_df, answered_correctly_u_sum, answered_correctly_q_sum, timestamp_u_incorrect)
 previous_test_df = test_df.copy()
test_df = test_df[test_df['content_type_id'] == 0].reset_index(drop = True)
 test_dataset = TestDataset(group, test_df, skills)
 test_dataloader = DataLoader(test_dataset, batch_size=51200, shuffle=False)
 SAKT_outs = []
for item in test_dataloader:
x = item[0].to(device ).long()
target_id = item[1].to(device ).long()
with torch.no_grad() :
output, att_weight = SAKT_model(x, target_id)
 output = torch.sigmoid(output)
 output = output[:, -1]
SAKT_outs.extend(output.view(-1 ).data.cpu().numpy())
 test_df['prior_question_had_explanation'].fillna(False, inplace=True)
 test_df.prior_question_had_explanation=test_df.prior_question_had_explanation.astype('int8')
 test_df['prior_question_elapsed_time'].fillna(prior_question_elapsed_time_mean, inplace=True)
 test_df = pd.merge(test_df, questions_df[['question_id', 'part']], left_on = 'content_id', right_on = 'question_id', how = 'left')
 test_df[TARGET] = 0
test_df = add_features(test_df, answered_correctly_u_count, answered_correctly_u_sum, elapsed_time_u_sum, explanation_u_sum, timestamp_u, timestamp_u_incorrect, answered_correctly_q_count, answered_correctly_q_sum, elapsed_time_q_sum, explanation_q_sum, answered_correctly_uq, update = False)
 sub_preds = np.zeros(test_df.shape[0])
 for i, model in enumerate(clfs, 1):
test_preds = model.predict(test_df[FEATURES])
 sub_preds += test_preds
lgbm_final = sub_preds / len(clfs)
 test_df[TARGET] = np.array(SAKT_outs)* 0.4 + lgbm_final * 0.6
set_predict(test_df[['row_id', TARGET]])
 print('Thanks')
 inference(TARGET, FEATURES, model, questions_df, prior_question_elapsed_time_mean, features_dicts )