本文介绍如何使用XGboost预测是否患有心脏病,涉及的数据有数值型和类别型。最后,使用了sklearn的自动超参数优化方法,寻找最优的超参数。
1 数据集导入与预处理
本次测试使用的是Kaggle上最近很火的预测心脏病的数据集,地址如下:
使用pandas导入输入集并查看数据格式:
1 | import pandas as pd |
Age | Sex | ChestPainType | RestingBP | Cholesterol | FastingBS | RestingECG | MaxHR | ExerciseAngina | Oldpeak | ST_Slope | HeartDisease | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 40 | M | ATA | 140 | 289 | 0 | Normal | 172 | N | 0.0 | Up | 0 |
1 | 49 | F | NAP | 160 | 180 | 0 | Normal | 156 | N | 1.0 | Flat | 1 |
2 | 37 | M | ATA | 130 | 283 | 0 | ST | 98 | N | 0.0 | Up | 0 |
3 | 48 | F | ASY | 138 | 214 | 0 | Normal | 108 | Y | 1.5 | Flat | 1 |
4 | 54 | M | NAP | 150 | 195 | 0 | Normal | 122 | N | 0.0 | Up | 0 |
1.1 认识数据集
1.1.1 认识特征
- 数据的整体
1 | features.shape |
可以看到,训练数据集有918个样本,11个特征,最后一列为标签值,标签为1代表患有心脏病,标签为0表示没有患有心脏病。
1 | features.info() |
1 | <class 'pandas.core.frame.DataFrame'> |
- 查看缺失数据情况
1 | features.isnull().sum() |
1 | Age 0 |
没有缺失数据!
- 类别数据查看
特征值取值上,有类别数据和连续值,我们通过unique()
查看类别数据的个数:
1 | features["Sex"].unique() |
数值型数据查看
1
features.describe()
得到的结果为:
Age | RestingBP | Cholesterol | FastingBS | MaxHR | Oldpeak | HeartDisease | |
---|---|---|---|---|---|---|---|
count | 918.000000 | 918.000000 | 918.000000 | 918.000000 | 918.000000 | 918.000000 | 918.000000 |
mean | 53.510893 | 132.396514 | 198.799564 | 0.233115 | 136.809368 | 0.887364 | 0.553377 |
std | 9.432617 | 18.514154 | 109.384145 | 0.423046 | 25.460334 | 1.066570 | 0.497414 |
min | 28.000000 | 0.000000 | 0.000000 | 0.000000 | 60.000000 | -2.600000 | 0.000000 |
25% | 47.000000 | 120.000000 | 173.250000 | 0.000000 | 120.000000 | 0.000000 | 0.000000 |
50% | 54.000000 | 130.000000 | 223.000000 | 0.000000 | 138.000000 | 0.600000 | 1.000000 |
75% | 60.000000 | 140.000000 | 267.000000 | 0.000000 | 156.000000 | 1.500000 | 1.000000 |
max | 77.000000 | 200.000000 | 603.000000 | 1.000000 | 202.000000 | 6.200000 | 1.000000 |
对于数值型数据,还可以查看他们之间的线性关联程度,相关系数的取值范围为[-1,1],属于0.8-1:极强相关;属于0.6-0.8:强相关;属于0.4-0.6:中等程度相关;属于0.2-0.4:弱相关;0-0.2:极弱相关或无相关。注意这是线性关联程度,只能作为参考。
1 | features.corr() |
Age | RestingBP | Cholesterol | FastingBS | MaxHR | Oldpeak | HeartDisease | |
---|---|---|---|---|---|---|---|
Age | 1.000000 | 0.254399 | -0.095282 | 0.198039 | -0.382045 | 0.258612 | 0.282039 |
RestingBP | 0.254399 | 1.000000 | 0.100893 | 0.070193 | -0.112135 | 0.164803 | 0.107589 |
Cholesterol | -0.095282 | 0.100893 | 1.000000 | -0.260974 | 0.235792 | 0.050148 | -0.232741 |
FastingBS | 0.198039 | 0.070193 | -0.260974 | 1.000000 | -0.131438 | 0.052698 | 0.267291 |
MaxHR | -0.382045 | -0.112135 | 0.235792 | -0.131438 | 1.000000 | -0.160691 | -0.400421 |
Oldpeak | 0.258612 | 0.164803 | 0.050148 | 0.052698 | -0.160691 | 1.000000 | 0.403951 |
HeartDisease | 0.282039 | 0.107589 | -0.232741 | 0.267291 | -0.400421 | 0.403951 | 1.000000 |
查看数据偏斜程度,用来描述数据分布形态的统计量,其描述的是某总体取值分布的对称性,简单来说就是数据的不对称程度。
(1)Skewness = 0 ,分布形态与正态分布偏度相同。
(2)Skewness > 0 ,正偏差数值较大,为正偏或右偏。长尾巴拖在右边,数据右端有较多的极端值。
(3)Skewness < 0 ,负偏差数值较大,为负偏或左偏。长尾巴拖在左边,数据左端有较多的极端值。
(4)数值的绝对值越大,表明数据分布越不对称,偏斜程度大。
1 | features.skew() |
1 | Age -0.195933 |
可以看到,FastingBS和Oldpeak两类数据的偏斜较大。
1.1.2 判断样本分布是否平衡
因为类别数据是0/1,所以通过如下式子计算样本分布是否均衡:
1 | sum(y) / len(y) |
样本是均衡的!
1.1.3 切分数据
倒数第1列label,其他列为特征:
1 | X = features.drop("HeartDisease",axis=1).copy() |
1.1.4 对类别特征进行one-hot编码
因为我们后续准备对数据采用xgboost的方式建模,所以在这里我们对类别数据进行ont-hot建模。首先需要说明一下,为什么1-N建模不可取,因为如果采用1-N建模,那么编码相近的类别会被认为联系更大,然而实际上这没有任何关系。需要说明的是,ont-hot编码只只适用于树模型,logsitc回归等模型不可以。代码如下:
1 | X_encoded = pd.get_dummies(X,columns=["ChestPainType","Sex","RestingECG","ST_Slope","ExerciseAngina"]) |
结果如下:
Age | RestingBP | Cholesterol | FastingBS | MaxHR | Oldpeak | ChestPainType_ASY | ChestPainType_ATA | ChestPainType_NAP | ChestPainType_TA | Sex_F | Sex_M | RestingECG_LVH | RestingECG_Normal | RestingECG_ST | ST_Slope_Down | ST_Slope_Flat | ST_Slope_Up | ExerciseAngina_N | ExerciseAngina_Y | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 40 | 140 | 289 | 0 | 172 | 0.0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 0 |
1 | 49 | 160 | 180 | 0 | 156 | 1.0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 |
2 | 37 | 130 | 283 | 0 | 98 | 0.0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 0 |
3 | 48 | 138 | 214 | 0 | 108 | 1.5 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 1 |
4 | 54 | 150 | 195 | 0 | 122 | 0.0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 0 |
主要关注原先是类别数据那几列,即”ChestPainType”,”Sex”,”RestingECG”,”ST_Slope”,”ExerciseAngina”。可以看到,对类别数据进行了ont-hot编码。
1.1.5 划分训练集和测试集
最后,我们划分一下训练集合和测试集合,为后续上模型预测做准备:
1 | from sklearn.model_selection import train_test_split |
查看一下划分的效果:
1 | sum(y_train) / len(y_train) |
嗯,分的不错!
2 XGboost的安装
xgboost和其他机器学习模型不一样,不能在sklearn中调用,而是有自己的包:
1 | pip install xgboost |
3 XGboost的简单使用
因为我们前面已经处理好了数据,因此直接套模型:
1 | import xgboost as xgb |
这就训练结束了,不出意外的话,可以达到0.93890的准确度。查看一下模型的混淆矩阵:
1 | from sklearn.metrics import plot_confusion_matrix |
可以看到,xgboost确实非常强大,随便训练一下,就可以得到很不错的结果。XGBClassifier中的各个参数意义参加:
https://www.cnblogs.com/wanglei5205/p/8579244.html
我们这里目标函数选择为二分类,返回概率,其他都是默认值。
4 XGboost的自动调参
上面使用的基本都是默认参数,那么如果想继续提升模型的预测精度,就需要进行手动调参了。
这里,我们使用了sklearn的自动调参工具GridSearchCV,听名字就知道这是采用网格搜索的方法进行调参的。这里,我们只需要在上面的基础上,把xgb.XGBClassifier类换成GridSearchCV类,其他都不变:
1 | from sklearn.model_selection import GridSearchCV |
当然,这里的param_grid参数值就是我们需要搜索的范围了,定义如下:
1 | param_grid = { |
按照和上述相同的方式就可以自动寻找最合适的超参数了。
完事以后,我们打印一下结果:
1 | print(optimal_params.best_params_) |