kaggle比赛【Riiid! Answer Correctness Prediction】

LGB,CatBoost,Random forest and Xgboost:参考开源代码:https://www.kaggle.com/andleebhayath/lgb-catboost-random-forest-and-xgboost

# Python 3环境安装了许多有用的分析库
#它是由kaggle/python Docker映像定义的:https://github.com/kaggle/docker-python
#例如,这里有几个有用的包要加载
import numpy as np # 线性代数
import pandas as pd # 数据处理,CSV文件I/O(例如pd.read_csv)

import os
for dirname, _, filenames in os.walk('/kaggle/input'):
    for filename in filenames:
        print(os.path.join(dirname, filename))
#你可以写入20GB的当前目录(/kaggle/working/),当你创建一个版本使用“保存和运行所有”时,它会作为输出保存下来。
#你也可以写临时文件到/kaggle/temp/,但是它们不会被保存到当前会话之外

Riiid! Answer Correctness Prediction

本笔记本的主要目标是给我们的数据和一些有用的功能的基本理解。

首先你可以在这里找到:

我们的数据的全面描述

特征工程

不需要对模型参数进行严格调整的LightGBM基线

import matplotlib.pyplot as plt

import warnings
warnings.simplefilter('ignore')

import plotly.express as px
from plotly.subplots import make_subplots
import plotly.graph_objs as go

import optuna
from optuna.samplers import TPESampler
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import train_test_split
from lightgbm import LGBMClassifier

import pandas as pd
from pandas.plotting import scatter_matrix
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.simplefilter('ignore')
from sklearn.metrics import roc_auc_score, confusion_matrix
from sklearn.model_selection import train_test_split, GridSearchCV, RandomizedSearchCV, learning_curve
from sklearn.utils import shuffle
import lightgbm as lgb
from lightgbm import LGBMClassifier
import eli5

from catboost import CatBoostClassifier
import xgboost as xgb




import riiideducation

%matplotlib inline
# for heatmap and other plots
colorMap1 = sns.color_palette("RdBu_r")
# for countplot and others plots
colorMap2 = 'Blues_r'

sampler = TPESampler(
    seed=666
)
types = {
        'row_id': 'int64', 
        'timestamp': 'int64', 
        'user_id': 'int32', 
        'content_id': 'int16', 
        'content_type_id': 'int8',
        'task_container_id': 'int16', 
        'user_answer': 'int8', 
        'answered_correctly': 'int8', 
        'prior_question_elapsed_time': 'float32', 
        'prior_question_had_explanation': 'boolean'
}
#载入数据集
train = pd.read_csv(
    '/kaggle/input/riiid-test-answer-prediction/train.csv', 
    low_memory=False, 
    nrows=10**6, 
    dtype=types
)
questions=pd.read_csv('/kaggle/input/riiid-test-answer-prediction/questions.csv')
lectures=pd.read_csv('/kaggle/input/riiid-test-answer-prediction/lectures.csv')
test=pd.read_csv('/kaggle/input/riiid-test-answer-prediction/example_test.csv')

train.head()

输出前几行的数据:

数据探索与EDA

train.csv 

row_id: (int64)行ID代码。

timestamp:(int64)从用户交互到该用户的第一个事件完成之间的时间,单位为毫秒。

user_id:(int32)用户的ID代码。

content_id:(int16)用户交互的ID代码

content_type_id: (int8) 如果事件是向用户提出一个问题则为0,如果事件是用户正在观看课程则为1。

task_container_id:(int16)问题或课程批次的Id代码。例如,用户可能会连续看到三个问题,然后才能看到其中任何一个问题的解释。这三个都会共享一个task_container_id。

user_answer:(int8)用户对问题的回答(如果有的话)。对于上课,将-1读成null。

answered_correct:(int8)如果用户回答正确。对于上课,将-1读为null。

prior_question_elapsed_time:(float32)用户回答前一个问题批次中的每个问题所花费的平均时间(以毫秒为单位),忽略中间的课程时间。为空,用于用户的第一个问题批次或讲座。请注意,时间是用户解决前一个批次中的每个问题所花费的平均时间。

prior_question_had_explanation:(bool)用户在回答前一个问题批次后是否看到解释和正确的回答,忽略中间的任何课程时间。该值在单个问题批次中共享,对于用户的第一个问题批次或讲座,该值为空。通常情况下,用户看到的前几个问题都是课堂测试的一部分,他们没有得到任何反馈。

1、打印训练集数量、特征数:有一百万条数据、10个特征  

print(f"Train shape: {train.shape}")

2、查看数据详细信息: 

train.describe().style.background_gradient(cmap='Blues')

输出结果:

解释:横轴是训练集的10个特征,纵轴分别显示这些特征的count(总数)、mean(平均值)、std(标准差)、min(最小值)、25%(前25%的数量)、50%(前50%的数量)、75%(前75%的数量)、max(最大值)

3、统计用户数量: 

print(f'Number of unique users: {len(np.unique(train.user_id))}')

虽然数据有一百万条、但是只有3824个用户。

4、查看缺失数据:

print(train.isnull().sum()%len(train))

由上图可知上prior_question_elspsed_time属性缺失23723条数据、prior_question_had_explanation属性缺失3816条数据。

5、检查一个相关矩阵,以获得列之间的更多信息

corr_matrix=train.corr()
corr_matrix['answered_correctly'].sort_values(ascending=True)

越接近1说明越是正相关,越接近-1越是负相关。与answered_correctly属性最相关的是prior_question_had_explanation属性、其次是prior_question_elspsed_time属性。content_type_id属性与answered_correctly属性最为负相关。

6、绘制相关性矩阵

plt.figure(figsize=(13,10))
sns.heatmap(corr_matrix,annot=True,
           linewidths=5,cmap=colorMap1)

 7、检查prior_question_elapsed_time的分布

plt.figure(figsize=(15, 10))
ax = sns.countplot(x="prior_question_elapsed_time", 
                   data=train[train['prior_question_elapsed_time'].notnull()],
                   palette=colorMap2)

8、检查一下我们的目标值回答问题的频率之间的联系

freq_answered_tasks = train['task_container_id'].value_counts().reset_index()
freq_answered_tasks.columns = [
    'task_container_id', 
    'freq'
]
train['freq_task_id'] = ''
train.loc[train['task_container_id'].isin(freq_answered_tasks[freq_answered_tasks['freq'] < 10000]['task_container_id'].values), 'freq_task_id'] = 'very rare answered'
train.loc[train['task_container_id'].isin(freq_answered_tasks[freq_answered_tasks['freq'] >= 10000]['task_container_id'].values), 'freq_task_id'] = 'rare answered'
train.loc[train['task_container_id'].isin(freq_answered_tasks[freq_answered_tasks['freq'] >= 50000]['task_container_id'].values), 'freq_task_id'] = 'normal answered'
train.loc[train['task_container_id'].isin(freq_answered_tasks[freq_answered_tasks['freq'] >= 200000]['task_container_id'].values), 'freq_task_id'] = 'often answered'
train.loc[train['task_container_id'].isin(freq_answered_tasks[freq_answered_tasks['freq'] >= 400000]['task_container_id'].values), 'freq_task_id'] = 'very often answered'

增加了新的特征[freq_answered_tasks]、取值有['very rare answered','rare answered','normal answered','often answered','very often answered']具体如何分组看上面代码的条件。

查看五条数据的结果:

train.sample(5)

 

9、查看freq_task_id= very rare answered 与 answere_correctly的统计关系

plt.figure(figsize=(15, 10))
sns.countplot(x='freq_task_id', hue='answered_correctly', data=train, palette=colorMap2)

由图可知、虽然有些人很少回答问题、但是回答正确数量还是挺多的。

10、查看回答正确/错误的占比

WIDTH=800
ds = train['answered_correctly'].value_counts().reset_index()

ds.columns = [
    'answered_correctly', 
    'percent_of_answers'
]

ds['percent_of_answers'] /= len(train)
ds = ds.sort_values(['percent_of_answers'])

fig = px.pie(
    ds, 
    names='answered_correctly', 
    values='percent_of_answers', 
    title='Percent of correct answers', 
    width=WIDTH,
    height=500 
)


fig.show()

11、prior_question_had_explanation与目标值具有中等相关性。看看他的分布

plt.figure(figsize=(15, 11))
ax = sns.countplot(x="prior_question_had_explanation", hue="answered_correctly", data=train[train['prior_question_had_explanation'].notnull()], palette=colorMap2)

prior_question_had_explanation:(bool)用户在回答前一个问题批次后是否看到解释和正确的回答。True表明这个用户上次回答问题后看到了正确答案,显然,上一次问题看到正确答案后,这次回答正确的占比比较高。False表明这个用户上次回答问题后没有看到正确答案,回答正确和错误的占比差不多。

显示的答案增加了成功回答的概率。

12、检查最活跃的user_id(前30个)

N=30

user_freq = train['user_id'].value_counts().reset_index()
user_freq.columns = [
    'user_id', 
    'count'
]

# Add ' - ' to convert user_id to str and not sort
user_freq['user_id'] = user_freq['user_id'].astype(str) + ' - '
user_freq = user_freq.sort_values(['count'], ascending=False).head(N)

plt.figure(figsize=(15, 15))
sns.barplot(x='count', y='user_id', data=user_freq, orient='h', palette=colorMap2)
plt.title(f'Top {N} the most active users', fontsize=14)

13、检查content_type_id中的分布:视频课程和问题的数量

WIDTH=800
ds = train['content_type_id'].value_counts().reset_index()

ds.columns = [
    'content_type_id', 
    'percent'
]

ds['percent'] /=len(train)

fig = px.pie(
    ds, 
    names='content_type_id', 
    values='percent', 
    title='Lecures & questions', 
    width=WIDTH,
    height=500 
)

fig.show()

content_type_id: (int8) 如果事件是向用户提出一个问题则为0,如果事件是用户正在观看课程则为1。说明98.00%的用户都在回答问题、1.99%的用户在观看课程。

14、显示用户回答问题的占比

ds=train['user_answer'].value_counts().reset_index()
ds.columns = [
    'user_answer', 
    'percent_of_answers'
]
ds['percent_of_answers']/=len(train)
ds = ds.sort_values(['percent_of_answers'])
fig = px.bar(
    ds, 
    x='user_answer', 
    y='percent_of_answers', 
    orientation='v', 
    title='Percent of user answers for every option', 
    width=WIDTH,
    height=400 
)

fig.show()

上图显示的是每个选项的用户回答百分比,-1表示在看课程视频,回答0个问题的有27.8%,回答1个问题的有26.7%,回答2个问题的有17.7%,回答3个问题的有25.7%。

15、

task_ids_freq = train['task_container_id'].value_counts().reset_index()
task_ids_freq.columns = ['task_container_id', 'count']

fig, ax = plt.subplots(figsize=(15, 10))

sns.pointplot(x='task_container_id', y='count', data=task_ids_freq, palette=colorMap2)
xticks_range = range(min(task_ids_freq['task_container_id']), 
                     max(task_ids_freq['task_container_id']),
                     1000)
plt.xticks(list(xticks_range), list(xticks_range))

16、Question.csv

question_id:训练/测试content_id列的外键,当内容类型为question(0)时。

bundle_id:一起提供问题的id码。

correct_answer:问题的答案。可以与train user_answer列进行比较,以检查用户是否正确。

part:问题的分类。

tag:问题的一个或多个详细的标签代码。标签的含义不会提供,但这些标签足以将问题聚在一起。

17、查看前几行数据

questions.head()

18、查看数据的详细信息

questions.describe().style.background_gradient(cmap='Blues')

统计question_id,bundle_id,correct_answer,part四个特征的总数、平均值,标准差,最小值,前25%,前50%,前75%,最大值。

19、查看缺失的数据量

print(questions.isnull().sum() % len(questions))

tags特征的数据缺失1条,其他特征的数据均未缺失。

20、查看回答正确的数量

questions['tag'] = questions['tags'].str.split(' ')
questions = questions.explode('tag')
questions = pd.merge(
    questions, 
    questions.groupby('question_id')['tag'].count().reset_index(), 
    on='question_id'
    )

questions = questions.drop(['tag_x'], axis=1)

questions.columns = [
    'question_id', 
    'bundle_id', 
    'correct_answer', 
    'part', 
    'tags', 
    'tags_number'
]
questions = questions.drop_duplicates()
ds = questions['correct_answer'].value_counts().reset_index()

ds.columns = [
    'correct_answer', 
    'number_of_answers'
]

ds['correct_answer'] = ds['correct_answer'].astype(str) + '-'
ds = ds.sort_values(['number_of_answers'])

fig = px.bar(
    ds, 
    x='number_of_answers', 
    y='correct_answer', 
    orientation='h', 
    title='Number of correct answers per group', 
    width=WIDTH,
    height=300
)
fig.show()

答对0个的有3716条,答对3个的有3544条,答对1个的有3478条,答对2个的有2785条。

21、查看问题类别的数量

ds = questions['part'].value_counts().reset_index()

ds.columns = [
    'part', 
    'count'
]

ds['part'] = ds['part'].astype(str) + '-'
ds = ds.sort_values(['count'])

fig = px.bar(
    ds, 
    x='count', 
    y='part', 
    orientation='h', 
    title='Parts distribution',
    width=WIDTH,
    height=400
)
fig.show()

问题分为7类、其中第5类的问题数量最多。第1类的问题数量最少

22、查看问题标签数量的分布

ds = questions['tags_number'].value_counts().reset_index()

ds.columns = [
    'tags_number', 
    'count'
]

ds['tags_number'] = ds['tags_number'].astype(str) + '-'
ds = ds.sort_values(['tags_number'])

fig = px.bar(
    ds, 
    x='count', 
    y='tags_number', 
    orientation='h', 
    title='Number tags distribution', 
    width=WIDTH,
    height=400 
    )

fig.show()

每个问题都至少有一个标签,有些问题有2、3、4、5、6个标签。有2个或6个标签的问题数量是最少的。

23、查看最有用的40个标签

check = questions['tags'].str.split(' ').explode('tags').reset_index()
check = check['tags'].value_counts().reset_index()

check.columns = [
    'tag', 
    'count'
]

check['tag'] = check['tag'].astype(str) + '-'
check = check.sort_values(['count']).tail(40)

fig = px.bar(
    check, 
    x='count', 
    y='tag', 
    orientation='h', 
     title='Top 40 most useful tags', 
    width=WIDTH,
    height=900 
)

fig.show()

lectures.head(10)

24、LECTURES.CSV

用户在学习过程中观看的讲课元数据。

lecture_id:训练/测试content_id列的外键,当内容类型为lecture(1)时。

part:课程的类别。

tags:讲座的一个标签代码。标签的含义将不会提供,但这些代码足以将讲座聚在一起。

type_of:简要描述课程的核心目的

25、查看数据的前几行

lectures.head(10)

26、查看缺失的数据

print('Part of missing values for every column')
print(lectures.isnull().sum() % len(lectures))

各个特征的数据都没有缺失

27、查看课程的核心目的的分布

lectures['type_of'].value_counts()

28、Test.csv

29、查看Test数据集的前几行

test.head()

特征工程

30、

train.head()

31、

features_df = train.iloc[:int(9/10 * len(train))]
train = train.iloc[int(9/10 * len(train)):]
train_questions_only_df = features_df[features_df['answered_correctly']!=-1]
grouped_by_user_df = train_questions_only_df.groupby('user_id')

user_answers_df = grouped_by_user_df.agg(
    {
        'answered_correctly': [
            'mean', 
            'count', 
            'std', 
            'median', 
            'skew'
        ]
    }
).copy()

user_answers_df.columns = [
    'mean_user_accuracy',
    'questions_answered',
    'std_user_accuracy', 
    'median_user_accuracy', 
    'skew_user_accuracy'
]
grouped_by_content_df = train_questions_only_df.groupby('content_id')
content_answers_df = grouped_by_content_df.agg(
    {
        'answered_correctly': [
            'mean', 
            'count', 
            'std', 
            'median', 
            'skew'
        ]
    }
).copy()

content_answers_df.columns = [
    'mean_accuracy', 
    'question_asked', 
    'std_accuracy', 
    'median_accuracy', 
    'skew_accuracy'
]
content_answers_df

32、

del features_df
del grouped_by_user_df
del grouped_by_content_df
features = [
    'mean_user_accuracy', 
    'questions_answered',
    'std_user_accuracy', 
    'median_user_accuracy',
    'skew_user_accuracy',
    'mean_accuracy', 
    'question_asked',
    'std_accuracy', 
    'median_accuracy',
    'prior_question_elapsed_time', 
    'prior_question_had_explanation',
    'skew_accuracy'
]

target = 'answered_correctly'
target

33、

train = train[train[target] != -1]
train = train.merge(user_answers_df, how='left', on='user_id')
train = train.merge(content_answers_df, how='left', on='content_id')
target

train['prior_question_had_explanation'] = train['prior_question_had_explanation'].fillna(value=False).astype(bool)
df = train.fillna(value=0.5)
col_to_drop = set(train.columns.values.tolist()).difference(features + [target])
for col in col_to_drop:
    del df[col]
df = df.replace([np.inf, -np.inf], np.nan)
df = df.fillna(0.5)

训练模型

34、

train_df, test_df, y_train, y_test = train_test_split(df[features], df[target], random_state=777, test_size=0.2)
params = {
    'num_leaves': 30, 
    'n_estimators': 300, 
    'min_data_in_leaf': 100, 
    'max_depth': 5, 
    'lambda': 0.0, 
    'feature_fraction': 1.0
}
model = LGBMClassifier(**params)
model.fit(train_df, y_train)

print('CatBoost ROC-AUC score: ', roc_auc_score(y_test.values, model_cat.predict_proba(test_df)[:, 1]))

预测结果:

35、随机森林

from sklearn.ensemble import RandomForestClassifier
rfclf = RandomForestClassifier()
rfclf.fit(train_df,y_train)
pred = rfclf.predict(test_df)
from sklearn.metrics import roc_auc_score
print(roc_auc_score(y_test,pred))

预测结果:

36、Xgboost

from xgboost import XGBClassifier
xgbclf = XGBClassifier()
xgbclf.fit(train_df,y_train)
xgb_pred = xgbclf.predict(test_df)

猜你喜欢

转载自blog.csdn.net/weixin_41950078/article/details/111564417