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/
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)
更多推荐
所有评论(0)