一、简介
1.背景介绍
在交通摩擦(事故)发生后,理赔员会前往现场勘察、采集信息,这些信息往往影响着车主是否能够得到保险公司的理赔。训练集数据包括理赔人员在现场对该事故方采集的36条信息,信息已经被编码,以及该事故方最终是否获得理赔。我们的任务是根据这36条信息预测该事故方没有被理赔的概率。
2.数据
- 数据文件
train.csv 训练集,文件大小 15.6mb
test.csv 预测集, 文件大小 6.1mb
sample_submit.csv 提交示例 文件大小 1.4mb
训练集中共有200000条样本,预测集中有80000条样本。 - 数据下载
下载链接:http://sofasofa.io/competition.php?id=2#c1跳转
3.变量说明
变量名 | 释义 |
---|---|
CaseId | 案例编号,没有实际意义 |
Q1 | 理赔员现场勘察采集的信息,Q1代表第一个问题的信息。信息被编码成数字,数字的大小不代表真实的关系。 |
Qk | 同上,Qk代表第k个问题的信息。一共36个问题。 |
Evaluation | 表示最终审核结果。0表示授予理赔,1表示未通过理赔审核。在test.csv中,这是需要被预测的标签。 |
4.评价方法
- 提交结果为每个测试样本未通过审核的概率,也就是Evaluation为1的概率。评价方法为精度-召回曲线下面积(Precision-Recall AUC),以下简称PR-AUC。
- PR-AUC的取值范围是0到1。越接近1,说明模型预测的结果越接近真实结果。
二、标杆模型
- 官方给了两个标杆模型:
http://sofasofa.io/benchmarks.php?id=2跳转
1.LASSO逻辑回归模型(Python)
import pandas as pd
from sklearn.linear_model import LogisticRegression
# 读取数据
train = pd.read_csv("train.csv")
test = pd.read_csv("test.csv")
submit = pd.read_csv("sample_submit.csv")
# 删除id
train.drop('CaseId', axis=1, inplace=True)
test.drop('CaseId', axis=1, inplace=True)
# 取出训练集的y
y_train = train.pop('Evaluation')
# 建立LASSO逻辑回归模型
clf = LogisticRegression(penalty='l1', C=1.0, random_state=0)
clf.fit(train, y_train)
y_pred = clf.predict_proba(test)[:, 1]
# 输出预测结果至my_LASSO_prediction.csv
submit['Evaluation'] = y_pred
submit.to_csv('my_LASSO_prediction.csv', index=False)
- 该模型预测结果的PR-AUC为:0.714644
2.随机森林分类模型(Python)
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
# 读取数据
train = pd.read_csv("train.csv")
test = pd.read_csv("test.csv")
submit = pd.read_csv("sample_submit.csv")
# 删除id
train.drop('CaseId', axis=1, inplace=True)
test.drop('CaseId', axis=1, inplace=True)
# 取出训练集的y
y_train = train.pop('Evaluation')
# 建立随机森林模型
clf = RandomForestClassifier(n_estimators=100, random_state=0)
clf.fit(train, y_train)
y_pred = clf.predict_proba(test)[:, 1]
# 输出预测结果至my_RF_prediction.csv
submit['Evaluation'] = y_pred
submit.to_csv('my_RF_prediction.csv', index=False)
- 该模型预测结果的PR-AUC为:0.850897
3.总结
因为该比赛的评价方法是通过计算PR-AUC进行比较。根据给出的两个不同的模型和其PR-AUC值,可以知道随机森林分类模型的PR-AUC是两个模型里最低的,所以我们直接对随机森林分类模型进行处理。
三、基础准备
1.混淆矩阵
2.PR-AUC的定义
3.PR-AUC的计算方法
- 使用sklearn.metrics.average_precision_score
>>> import numpy as np
>>> from sklearn.metrics import average_precision_score
>>> y_true = np.array([0, 0, 1, 1])
>>> y_predict = np.array([0.1, 0.4, 0.35, 0.8])
>>> average_precision_score(y_true, y_predict)
0.791666666
四、数据预处理
1.缺失值
代码:
print(train.info())
结果:
可以看到结果图最后一行返回的是“None”,也就是说没有缺失值!
- 若是有缺失值,可以用下面这行代码进行剔除:
dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)
更多关于缺失值的操作:https://blog.csdn.net/qq_41780234/article/details/102794601传送门
2.观察变量信息
代码:
print(train.describe())
结果:
3.相关系数查看
代码:
#导入numpy库
#补充在在最开始导入库的版块里
import numpy as np
#格式:corr=文件名.corr
#0.2只是我的建议范围,波动范围在0.0~1.0
corr = train.corr()
corr[np.abs(corr) < 0.2] = np.nan #绝对值低于0.2的就用nan替代
print(corr)
结果:
之所以选择0.2是因为:0.2-0.4弱正相关;0.4-0.6算中等相关;0.6-0.8达到强正相关。可以看出不同变量之间的关联不大。
4.重复值
代码:
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
import xgboost as xgb
from sklearn.metrics import accuracy_score
train = pd.read_csv(r"E:\my code\train.csv")
test = pd.read_csv(r"E:\my code\test.csv")
submit = pd.read_csv(r"E:\my code\sample_submit.csv")
# 去掉没有意义的一列
train.drop('CaseId', axis=1, inplace=True)
train.drop_duplicates(subset=None,keep='first',inplace=True)
print(train)
结果:
五、随机森林模型调参
1.交叉验证
数据集上实现一个分类森林,用随机森林训练并进行交叉验证:
#导入必要的包
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split,GridSearchCV,cross_val_score
from sklearn.metrics import accuracy_score
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# 读取数据
train = pd.read_csv(r"E:\my code\train.csv")
test = pd.read_csv(r"E:\my code\test.csv")
submit = pd.read_csv(r"E:\my code\sample_submit.csv")
#导入数据集
data = load_digits()
x = data.data
y = data.target
RF = RandomForestClassifier(random_state = 66)
score = cross_val_score(RF,x,y,cv=10).mean()
print('交叉验证得分: %.4f'%score)
结果:
交叉验证的得分为0.9460
2.选择criterion参数
这个参数只有两个参数 ‘entropy’(熵) 和 ‘gini’(基尼系数)可选,虽然但是,一般默认为gini
代码:
RF = RandomForestClassifier(random_state = 66)
score = cross_val_score(RF,x,y,cv=10).mean()
print('基尼系数得分: %.4f'%score)
RF = RandomForestClassifier(criterion = 'entropy',random_state = 66)
score = cross_val_score(RF,x,y,cv=10).mean()
print('熵得分: %.4f'%score)
结果:
3.选择n_estimators的最佳值
代码:
###调n_estimators参数
ScoreAll = []
for i in range(10,200,10):
DT = RandomForestClassifier(n_estimators = i,random_state = 66) #,criterion = 'entropy'
score = cross_val_score(DT,data.data,data.target,cv=10).mean()
ScoreAll.append([i,score])
ScoreAll = np.array(ScoreAll)
max_score = np.where(ScoreAll==np.max(ScoreAll[:,1]))[0][0] ##这句话看似很长的,其实就是找出最高得分对应的索引
print("最优参数以及最高得分:",ScoreAll[max_score])
plt.figure(figsize=[20,5])
plt.plot(ScoreAll[:,0],ScoreAll[:,1])
plt.show()
结果:
最优参数以及最高得分: [150.0.94990999]
4.缩小n_estimators最优值范围
代码:
###进一步缩小范围,调n_estimators参数
ScoreAll = []
for i in range(100,160):
DT = RandomForestClassifier(n_estimators = i,random_state = 66) #criterion = 'entropy',
score = cross_val_score(DT,data.data,data.target,cv=10).mean()
ScoreAll.append([i,score])
ScoreAll = np.array(ScoreAll)
max_score = np.where(ScoreAll==np.max(ScoreAll[:,1]))[0][0] ##这句话看似很长的,其实就是找出最高得分对应的索引
print("最优参数以及最高得分:",ScoreAll[max_score])
plt.figure(figsize=[20,5])
plt.plot(ScoreAll[:,0],ScoreAll[:,1])
plt.show()
结果:
最优参数以及最高得分: [151.0.95102421];可以看到,151为得分最高点,我们暂定n_estimators为151。
5.选择max_depth最优值
代码:
###粗调max_depth参数
ScoreAll = []
for i in range(10,30,3):
DT = RandomForestClassifier(n_estimators = 151,random_state = 66,max_depth =i ) #,criterion = 'entropy'
score = cross_val_score(DT,data.data,data.target,cv=10).mean()
ScoreAll.append([i,score])
ScoreAll = np.array(ScoreAll)
max_score = np.where(ScoreAll==np.max(ScoreAll[:,1]))[0][0] ##这句话看似很长的,其实就是找出最高得分对应的索引
print("最优参数以及最高得分:",ScoreAll[max_score])
plt.figure(figsize=[20,5])
plt.plot(ScoreAll[:,0],ScoreAll[:,1])
plt.show()
结果:
最优参数以及最高得分: [19.0.95102421]
6.缩小max_depth最优值的范围
转折点在19,但是19之后一直没有变化,可以说明就算不限制,所有树的最大深度也就是19左右,因为是以步长为3搜索的,所以还需要进行下一步搜索一下19附近的值。
(1)第一次缩范围:调节步长
代码:
ScoreAll = []
for i in range(10,30,1): #把步长调为1
DT = RandomForestClassifier(n_estimators = 151,random_state = 66,max_depth =i ) #,criterion = 'entropy'
score = cross_val_score(DT,data.data,data.target,cv=10).mean()
ScoreAll.append([i,score])
ScoreAll = np.array(ScoreAll)
max_score = np.where(ScoreAll==np.max(ScoreAll[:,1]))[0][0] ##这句话看似很长的,其实就是找出最高得分对应的索引
print("最优参数以及最高得分:",ScoreAll[max_score])
plt.figure(figsize=[20,5])
plt.plot(ScoreAll[:,0],ScoreAll[:,1])
plt.show()
结果:
(2)第二次缩范围:调节范围
代码:
ScoreAll = []
for i in range(15,20,1):
DT = RandomForestClassifier(n_estimators = 151,random_state = 66,max_depth =i ) #,criterion = 'entropy'
score = cross_val_score(DT,data.data,data.target,cv=10).mean()
ScoreAll.append([i,score])
ScoreAll = np.array(ScoreAll)
max_score = np.where(ScoreAll==np.max(ScoreAll[:,1]))[0][0] ##这句话看似很长的,其实就是找出最高得分对应的索引
print("最优参数以及最高得分:",ScoreAll[max_score])
plt.figure(figsize=[20,5])
plt.plot(ScoreAll[:,0],ScoreAll[:,1])
plt.show()
结果:
最优参数以及最高得分: [17.0.95102421];精细搜索之后发现,17这个值就是转折点,所以暂定max_depth = 17。
7.选择min_samples_split的最佳参数
因为min_samples_split最小值就是2,所以直接从2开始调起。
代码:
###调min_samples_split参数
ScoreAll = []
for i in range(2,10):
RF = RandomForestClassifier(n_estimators = 151,random_state = 66,max_depth =17,min_samples_split = i ) #,criterion = 'entropy'
score = cross_val_score(RF,data.data,data.target,cv=10).mean()
ScoreAll.append([i,score])
ScoreAll = np.array(ScoreAll)
max_score = np.where(ScoreAll==np.max(ScoreAll[:,1]))[0][0] ##这句话看似很长的,其实就是找出最高得分对应的索引
print("最优参数以及最高得分:",ScoreAll[max_score])
plt.figure(figsize=[20,5])
plt.plot(ScoreAll[:,0],ScoreAll[:,1])
plt.show()
结果:
最优参数以及最高得分: [2. 0.95102421];可以看到,随着min_samples_split增大,模型得分下降,说明没有出现过拟合现象,min_samples_split暂定2。
8.选择min_samples_leaf的最佳参数
代码:
###调min_samples_leaf参数
ScoreAll = []
for i in range(1,15,2):
DT = RandomForestClassifier(n_estimators = 151,random_state = 66,max_depth =17,min_samples_leaf = i,min_samples_split = 2 )
score = cross_val_score(DT,data.data,data.target,cv=10).mean()
ScoreAll.append([i,score])
ScoreAll = np.array(ScoreAll)
max_score = np.where(ScoreAll==np.max(ScoreAll[:,1]))[0][0] ##这句话看似很长的,其实就是找出最高得分对应的索引
print("最优参数以及最高得分:",ScoreAll[max_score])
plt.figure(figsize=[20,5])
plt.plot(ScoreAll[:,0],ScoreAll[:,1])
plt.show()
结果:
最优参数以及最高得分: [1. 0.95102421]
9.max_features的调参
代码:
#调max_features参数
param_grid = {
'max_features':np.arange(0.1, 1)}
rfc = RandomForestClassifier(random_state=66,n_estimators = 151,max_depth = 17,min_samples_leaf =1 ,min_samples_split =2 )
GS = GridSearchCV(rfc,param_grid,cv=10)
GS.fit(data.data,data.target)
print(GS.best_params_)
print(GS.best_score_)
结果:
{‘max_features’: 0.1}
0.9526877715704531
10.最佳参数汇总
参数 | 最优值 |
---|---|
n_estimators | 151 |
max_depth | 17 |
min_samples_split | 2 |
min_samples_leaf | 1 |
max_features | 0.1 |
六、最优参数附近进行小范围网格搜索
因为手动调参时,这些参数可能会相互影响,导致得到的参数还不是最优的。所以在最优参数附近进行小范围的网格搜索,排出相互影响的因素。
但这次的数据量巨大,不需要网格搜索,且耗时巨长,博主跑了一个下午都没出结果,遂决定放弃。
七、随机森林的最终结果
代码:
#导入必要的包
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split,GridSearchCV,cross_val_score
from sklearn.metrics import accuracy_score
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# 读取数据
train = pd.read_csv(r"E:\my code\train.csv")
test = pd.read_csv(r"E:\my code\test.csv")
submit = pd.read_csv(r"E:\my code\sample_submit.csv")
#导入数据集
data = load_digits()
x = data.data
y = data.target
# 删除id
train.drop('CaseId', axis=1, inplace=True)
test.drop('CaseId', axis=1, inplace=True)
# 取出训练集的y
y_train = train.pop('Evaluation')
# 建立随机森林模型
clf = RandomForestClassifier(random_state=66,n_estimators = 151,max_depth = 17,min_samples_leaf =1 ,min_samples_split =2 )
clf.fit(train, y_train)
y_pred = clf.predict_proba(test)[:, 1]
# 输出预测结果至my_RF_prediction.csv
submit['Evaluation'] = y_pred
submit.to_csv('my_RF_prediction3.csv', index=False)
结果:
结果不尽人意,比标杆模型的auc还低 QAQ
八、Xgboost模型优化
1.特征工程——整体相关性分析
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split,GridSearchCV,cross_val_score
from sklearn.metrics import accuracy_score
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sn
# 读取数据
train = pd.read_csv(r"E:\my code\train.csv")
test = pd.read_csv(r"E:\my code\test.csv")
submit = pd.read_csv(r"E:\my code\sample_submit.csv")
sn.heatmap(train.corr())
plt.show()
放大右下角:
2.最后的模型
代码:
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
import xgboost as xgb
from sklearn.metrics import accuracy_score
traindata = pd.read_csv(r"E:\my code\train.csv")
testdata = pd.read_csv(r"E:\my code\test.csv")
submitdata = pd.read_csv(r"E:\my code\sample_submit.csv")
# 去掉没有意义的一列
traindata.drop('CaseId', axis=1, inplace=True)
testdata.drop('CaseId', axis=1, inplace=True)
# 从训练集中分类标签
trainlabel = traindata['Evaluation']
traindata.drop('Evaluation', axis=1, inplace=True)
traindata1, testdata1, trainlabel1 = traindata.values, testdata.values, trainlabel.values
# 数据集分割
X_train, X_test, y_train, y_test = train_test_split(traindata1, trainlabel1,
test_size=0.3, random_state=123457)
# 训练模型
model = xgb.XGBClassifier(max_depth=5,
learning_rate=0.1,
min_child_weight=4,
gamma=0.5,
n_estimators=5000,
silent=True,
objective='binary:logistic',
nthread=4,
seed=27,
scale_pos_weight=1,
subsample=0.9,
colsample_bytree=0.6,
reg_alpha=10,
colsample_bylevel=1,
base_score=0.5,
)
model.fit(X_train, y_train)
# 对测试集进行预测
y_pred = model.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print('accuracy:%2.f%%' % (accuracy * 100))
#查看AUC评价标准
from sklearn import metrics
#必须二分类才能计算
print("AUC Score (Train): %f" % metrics.roc_auc_score(y_test, y_pred))
def run_predict():
y_pred_test = model.predict_proba(testdata1)[:, 1]
# 保存预测的结果
submitData = pd.read_csv(r"E:\my code\sample_submit.csv")
submitData['Evaluation'] = y_pred_test
submitData.to_csv("xgboost9.csv", index=False)
run_predict()
多次调整后:
= =