【2023天池龙珠计划】机器学习训练营(二):XGBoost

一、概述

参考资料:https://tianchi.aliyun.com/notebook/170915

XGBoost 的主要优点:

  1. 简单易用。相对其他机器学习库,用户可以轻松使用 XGBoost 并获得相当不错的效果。
  2. 高效可扩展。在处理大规模数据集时速度快效果好,对内存等硬件资源要求不高。
  3. 鲁棒性强。相对于深度学习模型不需要精细调参便能取得接近的效果。
  4. XGBoost 内部实现提升树模型,可以自动处理缺失值

XGBoost 的主要缺点:

  1. 相对于深度学习模型无法对时空位置建模,不能很好地捕获图像、语音、文本等高维数据
  2. 在拥有海量训练数据,并能找到合适的深度学习模型时,深度学习的精度可以遥遥领先 XGBoost

XGBoost 的主要应用场景:

XGBoost 还被成功应用在工业界与学术界的各种问题中。例如商店销售额预测、高能物理事件分类、web 文本分类;用户行为预测、运动检测、广告点击率预测、恶意软件分类、灾害风险预测、在线课程退学率预测。

二、核心代码流程

(一)库文件导入、数据获取与处理

首先导入 numpypandas 等基础数据函数库,
接着导入matplotlibseaborn等绘图函数库。

## 基础函数库
import numpy as np
import pandas as pd
## 绘图函数库
import matplotlib.pyplot as plt
import seaborn as sns
## 为了正确评估模型性能,将数据划分为训练集和测试集,并在训练集上训练模型,在测试集上验证模型性能。
from sklearn.model_selection import train_test_split

接着读取数据文件,并将其处理为数据集。

## 我们利用Pandas自带的read_csv函数读取并转化为DataFrame格式
data = pd.read_csv('train.csv')
"""
## 利用.info()查看数据的整体信息
data.info()
## 对于特征进行一些统计描述
data.describe()
## 利用value_counts函数查看训练集标签的数量
pd.Series(data['RainTomorrow']).value_counts()

## 查看前5条数据
data.head()
## 查看后五条数据
data.tail()
"""

## 选择其类别为0和1的样本 (不包括类别为2的样本)
data_target_part = data['RainTomorrow']
data_features_part = data[[x for x in data.columns if x != 'RainTomorrow']]

## 测试集大小为20%, 80%/20%分
x_train, x_test, y_train, y_test = train_test_split(data_features_part, data_target_part, test_size = 0.2, random_state = 2020)

数据预处理也不仅限于数据集的切分,此外还包括数值的处理:

  1. 原始数据集有部分 NaN 的数据。这里将他们清洗为“-1”。
  2. 同时由于 XGBoost 无法处理字符串类型的数据,我们需要一些方法将字符串数据转化为数值型数据

一种最简单的方法是把所有的相同类别的特征编码成同一个值,例如女=0,男=1,狗狗=2,所以最后编码的特征值是在 [ 0 , 特征数量 − 1 ] [0, 特征数量-1] [0,特征数量1]之间的整数。
除此之外,还有独热编码、求和编码、留一法编码等等方法可以获得更好的效果。

## 处理 NaN 数据
data = data.fillna(-1)

## 把所有的相同类别的特征编码为同一个值
def get_mapfunction(x):
    mapp = dict(zip(x.unique().tolist(),
         range(len(x.unique().tolist()))))
    def mapfunction(y):
        if y in mapp:
            return mapp[y]
        else:
            return -1
    return mapfunction
for i in category_features:
    data[i] = data[i].apply(get_mapfunction(data[i]))

# 将标签的"Yes"和"No"处理为数值
def transfer(x):
    if x == 'No':
        return 0
    elif x == 'Yes':
        return 1
    else:
        return -1

y_test = y_test.apply(transfer)
y_train = y_train.apply(transfer)

"""
data[i] === data['Location'] 是一个一维的DF对象。
apply() 需要外部传入一个函数对象,该函数对象需要一个参数,一个返回值。如"mapfunction"所示.

## 编码后的字符串特征变成了数字
data['Location'].unique()
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
       17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
       34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48])
"""

(二)模型训练

## 导入XGBoost模型
from xgboost.sklearn import XGBClassifier
## 定义 XGBoost模型
clf = XGBClassifier()
# 在训练集上训练XGBoost模型
clf.fit(x_train, y_train)

(三)模型验证

## 在训练集和测试集上分布利用训练好的模型进行预测
train_predict = clf.predict(x_train)
test_predict = clf.predict(x_test)
from sklearn import metrics

## 利用accuracy(准确度)【预测正确的样本数目占总预测样本数目的比例】评估模型效果
print('The accuracy of the Logistic Regression is:',metrics.accuracy_score(y_train,train_predict))
print('The accuracy of the Logistic Regression is:',metrics.accuracy_score(y_test,test_predict))

## 查看混淆矩阵 (预测值和真实值的各类情况统计矩阵)
confusion_matrix_result = metrics.confusion_matrix(test_predict,y_test)
print('The confusion matrix result:\n',confusion_matrix_result)

# 利用热力图对于结果进行可视化
plt.figure(figsize=(8, 6))
sns.heatmap(confusion_matrix_result, annot=True, cmap='Blues')
plt.xlabel('Predicted labels')
plt.ylabel('True labels')
plt.show()

"""
The accuracy of the Logistic Regression is: 0.8982476703979371
The accuracy of the Logistic Regression is: 0.8575179333302076
The confusion matrix result:
 [[15656  2142]
 [  897  2634]]
 15656 + 2634 个正确, 897 + 2142 个错误。
"""

输出的图片结果如下:
在这里插入图片描述

三、辅助代码流程

(一)基础工作,特征分类

当然,这部分工作通常应该在模型训练之前,就本次代码而言的顺序应该为:“数据读取->数据预处理(NaN)->辅助分析->数据预处理(文本数据)->模型训练->模型验证”

在本节中,数据集的特征维度较多,需要提前对数据集的特征维度进行分类。这里将特征分为“数值类特征”与“字符类特征”。

# 筛选数值型属性
numerical_features = [x for x in data.columns if data[x].dtype == np.float]
print(numerical_features)
"""
['MinTemp', 'MaxTemp', 'Rainfall', 'Evaporation', 'Sunshine', 'WindGustSpeed', 'WindSpeed9am', 'WindSpeed3pm', 'Humidity9am', 'Humidity3pm', 'Pressure9am', 'Pressure3pm', 'Cloud9am', 'Cloud3pm', 'Temp9am', 'Temp3pm']
"""

# 筛选非数值型属性 标签是"RainTomorrow",需要区分开
category_features = [x for x in data.columns if data[x].dtype != np.float and x != 'RainTomorrow']
print(category_features)
"""
['Date', 'Location', 'WindGustDir', 'WindDir9am', 'WindDir3pm', 'RainToday']
"""

(二)散点图:属性两两对比

要分析两个属性对分类结果的影响,可以采用散点图方式。

## 选取三个特征与标签组合的散点可视化
sns.pairplot(data=data[['Rainfall', 'Evaporation', 'Sunshine', 'RainTomorrow']], diag_kind='hist', hue= 'RainTomorrow')
plt.show()

输出散点图如下:
在这里插入图片描述
在图中可以看到,Sunshine数值越低,下雨(橙色点)就越密集。

(三)箱型图:分析不同特征分布差异

利用箱型图得出,使用不同类别不同特征上的分布差异情况。
可以发现 Sunshine,Humidity3pm,Cloud9am,Cloud3pm 的区分能力较强。

for col in data[numerical_features].columns:
    if col != 'RainTomorrow':
        sns.boxplot(x='RainTomorrow', y=col, saturation=0.5, palette='pastel', data=data)
        plt.title(col)
        plt.show()

部分箱型图的部分结果如下:
在这里插入图片描述

(四)次数统计:常用于离散型数据

统计两种标签,所有特征的出现次数。

tlog = {}
for i in category_features:
    tlog[i] = data[data['RainTomorrow'] == 'Yes'][i].value_counts()
flog = {}
for i in category_features:
    flog[i] = data[data['RainTomorrow'] == 'No'][i].value_counts()

"""
单个 value_counts() 返回的对象是一个ValueCounts对象。
print该对象,有三个属性:{主体数据, Name, dtype}

如下:

{'Date': 2010/9/3      29
 2009/6/2      27
 2012/7/10     27
 2015/9/2      27
 2013/6/12     26
               ..
 2008/10/5      1
 2015/10/6      1
 2010/1/15      1
 2007/11/30     1
 2008/9/16      1
 Name: Date, Length: 3163, dtype: int64
 ...}
"""

统计完特征次数后,进行可视化展示。

# 设定图片大小
plt.figure(figsize=(10,10))

# 绘制图片A
plt.subplot(1,2,1)
plt.title('RainTomorrow')
sns.barplot(x = pd.DataFrame(tlog['Location']).sort_index()['Location'], y = pd.DataFrame(tlog['Location']).sort_index().index, color = "red")

# 绘制图片B
plt.subplot(1,2,2)
plt.title('Not RainTomorrow')
sns.barplot(x = pd.DataFrame(flog['Location']).sort_index()['Location'], y = pd.DataFrame(flog['Location']).sort_index().index, color = "blue")

"""
xxx['Location']时,理论上是获取一维DF对象。但这里在print时,会把Key也打印出来。

x = pd.DataFrame(flog['Location']).sort_index()['Location']
Adelaide            513
Albany              665
Albury              454
AliceSprings        169
BadgerysCreek       425
Ballarat            597
Bendigo             418
Brisbane            529
Cairns              700
Canberra            475
Cobar               305
CoffsHarbour        677
Dartmoor            679
Darwin              645
GoldCoast           569
Hobart              579
Katherine           214
Launceston          506
Melbourne           478
MelbourneAirport    493
Mildura             246
Moree               293
MountGambier        692
MountGinini         623
Newcastle           555
Nhil                179
NorahHead           607
NorfolkIsland       669
Nuriootpa           444
PearceRAAF          389
Penrith             451
Perth               474
PerthAirport        425
Portland            818
Richmond            404
Sale                479
SalmonGums          352
Sydney              642
SydneyAirport       573
Townsville          362
Tuggeranong         430
Uluru                96
WaggaWagga          396
Walpole             722
Watsonia            567
Williamtown         532
Witchcliffe         663
Wollongong          542
Woomera             143
Name: Location, dtype: int64

y = pd.DataFrame(flog['Location']).sort_index().index
Index(['Adelaide', 'Albany', 'Albury', 'AliceSprings', 'BadgerysCreek',
       'Ballarat', 'Bendigo', 'Brisbane', 'Cairns', 'Canberra', 'Cobar',
       'CoffsHarbour', 'Dartmoor', 'Darwin', 'GoldCoast', 'Hobart',
       'Katherine', 'Launceston', 'Melbourne', 'MelbourneAirport', 'Mildura',
       'Moree', 'MountGambier', 'MountGinini', 'Newcastle', 'Nhil',
       'NorahHead', 'NorfolkIsland', 'Nuriootpa', 'PearceRAAF', 'Penrith',
       'Perth', 'PerthAirport', 'Portland', 'Richmond', 'Sale', 'SalmonGums',
       'Sydney', 'SydneyAirport', 'Townsville', 'Tuggeranong', 'Uluru',
       'WaggaWagga', 'Walpole', 'Watsonia', 'Williamtown', 'Witchcliffe',
       'Wollongong', 'Woomera'],
      dtype='object')
"""

# 开始绘制
plt.show()

统计的特征次数图如下:
在这里插入图片描述

四、网格搜索训练流程

相较于“核心代码流程”中的方法,这里有一种网格搜索训练说不定能取得更好的效果。对于XGBoost而言,其中包括但不限于下列对模型影响较大的参数:

  1. learninfg_rate: 有时也叫作 eta,系统默认值为 0.3。每一步迭代的步长,很重要。太大了运行准确率不高,太小了运行速度慢
  2. subsample:系统默认为 1。这个参数控制对于每棵树,随机采样的比例。减小这个参数的值,算法会更加保守,避免过拟合, 取值范围零到一。
  3. colsample_bytree:系统默认值为 1。我们一般设置成 0.8 左右。用来控制每棵随机采样的列数的占比(每一列是一个特征)。
  4. max_depth: 系统默认值为 6,我们常用 3-10 之间的数字。这个值为树的最大深度。这个值是用来控制过拟合的。max_depth 越大,模型学习的更加具体

(一)网格搜索最佳训练参数

网格搜索训练代码

## 从sklearn库中导入网格调参函数
from sklearn.model_selection import GridSearchCV

## 定义参数取值范围
learning_rate = [0.1, 0.3, 0.6]
subsample = [0.8, 0.9]
colsample_bytree = [0.6, 0.8]
max_depth = [3,5,8]

parameters = { 'learning_rate': learning_rate,
              'subsample': subsample,
              'colsample_bytree':colsample_bytree,
              'max_depth': max_depth}
model = XGBClassifier(n_estimators = 50)

## 进行网格搜索
clf = GridSearchCV(model, parameters, cv=3, scoring='accuracy',verbose=1,n_jobs=-1)
clf = clf.fit(x_train, y_train)

打印出最好的参数

## 网格搜索后的最好参数为
print(clf.best_params_)

(二)使用最佳参数进行训练学习

使用最好的参数进行训练与学习

## 在训练集和测试集上分布利用最好的模型参数进行预测

## 定义带参数的 XGBoost模型
clf = XGBClassifier(colsample_bytree = 0.6, learning_rate = 0.3, max_depth= 8, subsample = 0.9)
# 在训练集上训练XGBoost模型
clf.fit(x_train, y_train)

train_predict = clf.predict(x_train)
test_predict = clf.predict(x_test)

## 利用accuracy(准确度)【预测正确的样本数目占总预测样本数目的比例】评估模型效果
print('The accuracy of the Logistic Regression is:',metrics.accuracy_score(y_train,train_predict))
print('The accuracy of the Logistic Regression is:',metrics.accuracy_score(y_test,test_predict))

## 查看混淆矩阵 (预测值和真实值的各类情况统计矩阵)
confusion_matrix_result = metrics.confusion_matrix(test_predict,y_test)
print('The confusion matrix result:\n',confusion_matrix_result)

# 利用热力图对于结果进行可视化
plt.figure(figsize=(8, 6))
sns.heatmap(confusion_matrix_result, annot=True, cmap='Blues')
plt.xlabel('Predicted labels')
plt.ylabel('True labels')
plt.show()

五、总结

相较于基础的“逻辑回归”而言,XGBoost如果要完成最核心的功能,在API的调用上并没有太大差别。但本次实验中,因为训练集数据的复杂性,所以有很多重要的辅助分析流程需要掌握。

比如对连续性数据可以使用:“散点图分析”、“箱型图分析”。
对于离散型数据可以使用:“次数统计”。

当然XGBoost也和其他高级的机器学习算法一样,有大量的训练参数。这里也涉及到了一种“网格搜索GridSearch”的办法,可以预先进行一次“试跑”,得出一组合适的训练参数,接着再使用这组合适的训练参数进行训练。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值