<jupyter_start><jupyter_text>Read Data<jupyter_code>def read_data():
    train_df = pd.read_csv(path/'train.csv')
    test_df = pd.read_csv(path/'test.csv')
    train_labels_df = pd.read_csv(path/'train_labels.csv')
    specs_df = pd.read_csv(path/'specs.csv')
    return train_df, test_df, train_labels_df, specs_df
train_df, test_df, train_labels_df, specs_df = read_data()
train_df.head()
test_df.head()
train_labels_df.head()
specs_df.head()<jupyter_output><empty_output><jupyter_text>Feature Engineering  Process train set<jupyter_code>main_keys = ['installation_id', 'game_session']
merge_args = {'left_index':True, 'right_index':True}
merged_train_df = pd.merge(train_df, train_labels_df, on=main_keys)<jupyter_output><empty_output><jupyter_text>Experiment with aggregations<jupyter_code>merged_train_df
merged_train_grouped_df = merged_train_df.groupby(['event_id', 'game_session', 'installation_id', 'title'])
merged_train_agg_df = merged_train_grouped_df.agg({'game_time': ['sum', 'mean'],
                                                   'event_code': lambda x:x.value_counts().index[0],
                                                   'event_count': ['sum', 'mean']})
merged_train_agg_df.reset_index()
def extract_time_features(df):
    df['timestamp'] = pd.to_datetime(df['timestamp'])
    df['month'] = df['timestamp'].dt.month
    df['hour'] = df['timestamp'].dt.hour
    df['year'] = df['timestamp'].dt.year
    df['dayofweek'] = df['timestamp'].dt.dayofweek
    df['weekofyear'] = df['timestamp'].dt.weekofyear
    df['dayofyear'] = df['timestamp'].dt.dayofyear
    df['quarter'] = df['timestamp'].dt.quarter
    return df

merged_train_df = extract_time_features(merged_train_df)
merged_train_df.head()
# Remove the timestamp column
merged_train_df = merged_train_df[[col for col in merged_train_df.columns if col not in ['timestamp', 'num_correct', 'num_incorrect', 'accuracy']]]
merged_train_df.head()
merged_train_df.columns
def convert_categorical_to_num(df, categorical_list):
    for cat_name in categorical_list:
        df[cat_name] = df[cat_name].astype('category')
    # Get categorical columns again
    cat_columns = df.select_dtypes(['category']).columns
    print('cat_columns', cat_columns)
    df[cat_columns] = df[cat_columns].apply(lambda x: x.cat.codes)

convert_categorical_to_num(merged_train_df, ['title', 'type', 'world', 'event_id'])
pd.options.display.max_columns = None
merged_train_df<jupyter_output><empty_output><jupyter_text>Process test set<jupyter_code>comp_test_df = extract_time_features(test_df)
comp_test_df.head()
comp_test_df = comp_test_df[[col for col in comp_test_df.columns if col not in ['timestamp']]]
comp_test_df.head()
convert_categorical_to_num(comp_test_df, ['title', 'type', 'world', 'event_id'])
comp_test_df.head()<jupyter_output><empty_output><jupyter_text>Checks<jupyter_code>comp_test_df.columns
merged_train_df.columns
merged_train_df.shape
comp_test_df.shape
comp_test_df['installation_id'].nunique()<jupyter_output><empty_output><jupyter_text>Training<jupyter_code># quadratic weighted kappa
def qwk3(a1, a2, max_rat=3):
    '''
    a1 - ground truth
    a2 - predicted values
    '''
    assert(len(a1) == len(a2))
    a1 = np.asarray(a1, dtype=int)
    a2 = np.asarray(a2, dtype=int)
    hist1 = np.zeros((max_rat + 1, ))
    hist2 = np.zeros((max_rat + 1, ))
    o = 0
    for k in range(a1.shape[0]):
        i, j = a1[k], a2[k]
        hist1[i] += 1
        hist2[j] += 1
        o +=  (i - j) * (i - j)
    e = 0
    for i in range(max_rat + 1):
        for j in range(max_rat + 1):
            e += hist1[i] * hist2[j] * (i - j) * (i - j)
    e = e / a1.shape[0]
    return 1 - o / e
features = [c for c in merged_train_df.columns if c not in ['accuracy_group', 'installation_id', 'game_session', 'event_data']]
target = 'accuracy_group'
features
num_splits = 10
params = {
    'learning_rate': 0.007,
    'metric': 'multiclass',
    'objective': 'multiclass',
    'num_classes': 4,
    'feature_fraction': 0.75,
    "bagging_fraction": 0.8,
    "bagging_seed": 42,
    'max_depth': 11
}

early_stopping_rounds = 100
num_boost_round = 1000 # should be around 11000 to get better results. This is just for quick testing
def train_model(comp_train_df):
    
    kf = KFold(n_splits=num_splits, shuffle=True)
    
    oof_pred = np.zeros((len(comp_train_df), 4))
    models = []
    best_qw3 = 0.0
    best_qw3_index = 0
    
    for fold, (tr_ind, val_ind) in enumerate(kf.split(comp_train_df)):
        print(f'Fold: {fold+1}')
        x_train, x_val = comp_train_df[features].iloc[tr_ind], comp_train_df[features].iloc[val_ind]
        y_train, y_val = comp_train_df[target][tr_ind], comp_train_df[target][val_ind]
        train_set = lgb.Dataset(x_train, y_train)
        val_set = lgb.Dataset(x_val, y_val)

        model = lgb.train(params, train_set, num_boost_round = num_boost_round, early_stopping_rounds = early_stopping_rounds, 
                          valid_sets=[train_set, val_set], verbose_eval = early_stopping_rounds)
        oof_pred[val_ind] = model.predict(x_val)
        models.append(model)
        
        val_crt_fold = qwk3(y_val, oof_pred[val_ind].argmax(axis = 1))
        print(f'Fold: {fold+1} quadratic weighted kappa score: {np.round(val_crt_fold,4)}')
        if best_qw3 < val_crt_fold:
            best_qw3 = val_crt_fold
            best_qw3_index = fold
        
    res = qwk3(comp_train_df['accuracy_group'], oof_pred.argmax(axis = 1))
    print(f'Quadratic weighted score: {np.round(res,4)}')
        
    return models, best_qw3_index
%%time
all_models, best_qw3_index = train_model(merged_train_df)
print(f'best model index: {best_qw3_index}')<jupyter_output><empty_output><jupyter_text>Inference<jupyter_code>grouped = comp_test_df.groupby('installation_id')
comp_test_tail_df = pd.concat([grouped.tail(1)]).sort_values('installation_id').reset_index(drop=True)
comp_test_tail_df
def run_predictions(models, df):
    y_pred = np.zeros((len(df), 4))
    for i, model in enumerate(models):
        y_pred += model.predict(df[features])
        print(f'Ran {i}th model ')
    return y_pred / num_splits
y_pred = run_predictions(all_models, comp_test_tail_df)
# y_pred = all_models[best_qw3_index].predict(comp_test_df[features])
assert comp_test_tail_df.shape[0] == y_pred.shape[0]
np.unique(y_pred.argmax(-1), return_counts=True)
comp_test_tail_df['accuracy_group'] = y_pred.argmax(-1)
comp_test_tail_df.shape, comp_test_tail_df.columns<jupyter_output><empty_output><jupyter_text>Create Submission<jupyter_code>def prepare_submission(submission_df, y_pred):
    sample_submission_df = pd.read_csv(path/'sample_submission.csv')
    sample_submission_df.drop('accuracy_group', inplace = True, axis = 1)
    sample_submission_df = sample_submission_df.merge(submission_df, on = 'installation_id')
    sample_submission_df = sample_submission_df[['installation_id', 'accuracy_group']]
    sample_submission_df.to_csv('submission.csv', index = False)
prepare_submission(comp_test_tail_df, y_pred)
!head submission.csv
!cat submission.csv | wc -l<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13184955627553177, 'fraction_numerical': 0.012677841949570362, 'mean_word_length': 4.608214849921011, 'pattern_counts': {'":': 2, '<': 34, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '8', 'dir': 'jupyter-structured-clean-dedup', 'id': '201104', 'license': 'Apache-2.0', 'n_tokens_mistral': 2708, 'n_tokens_neox': 2620, 'n_words': 431, 'path': 'nbs_gil/data_science_bowl/data_science_bowl_training_8_miguel_approach.ipynb', 'repo_name': 'gilfernandes/fastai-exercises', 'size': '7099'}