XGBoost - 算法理论以及实例
作者:互联网
XGBoost是一种基于Boost算法的机器学习方法,全称EXtreme Gradient Boosting。
XGBoost在GBDT的基础上,引入了:
- CART回归树
- 正则项
- 泰勒公式二阶导数
- Blocks数据结构(用于加速运算)
从而实现了比GBDT更好的实现效果。
一. 理论
关于XGBoost的理论在官网上介绍地很清楚,可以参考: https://xgboost.readthedocs.io/en/stable/tutorials/model.html
函数模型
XGBoost 的目标模型可以表示为:
其中L(θ)为损失项,Ω(θ)为正则项。正则项反映了模型的复杂程度。
一般L(θ)可以用方差来进行统计:
用于逻辑回归中:
下图可以解释两者和模型匹配程度之间的关系:
回归树
XGBoost树集成模型由一组分类和回归树 (CART) 组成。下面是一个 CART 的简单示例,用于对某人是否会喜欢假设的电脑游戏 X 进行分类。
我们将一个家族的成员分类为不同的叶子,并给他们分配相应叶子上的分数。CART 与决策树略有不同,在决策树中,叶仅包含决策值。在CART中,每片叶子都有一个真实的分数,这给了我们更丰富的解释,超越了分类。这也允许采用有原则的统一优化方法,我们将在本教程的后面部分中看到。
通常,一棵树不够坚固,无法在实践中使用。实际使用的是集成模型,它将多个树的预测相加。
在数学上,我们可以将模型写成
其中K是树的数量,f(x)是函数空间中的函数,并且是所有可能的 CART 的集合。要优化的目标函数由下式给出
XGBoost
下面给出用XGBoost求解的步骤,这部分参考:
https://zhuanlan.zhihu.com/p/162001079
一:重新定义一棵树
二:定义这棵树的复杂度
三:分组节点
合并一次项系数、二次项系数。
四:求解目标值
优化目标即让Obj的值尽可能的小
分裂点选择
训练树时,分裂点的选择有如下几种算法:
- 贪心算法
- 近似算法
- 加权分位数草图算法
- 稀疏感知法
二. 实例
用XGBoost做回归:
用TPS2022 Mar的题目做示例,用过时间预测道路拥堵程度:
原始数据
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.pipeline import make_pipeline
from sklearn.metrics import mean_absolute_error, mean_squared_error
train_orig = pd.read_csv('train.csv', index_col='row_id', parse_dates=['time'])
train_orig.head()
特征工程
%%time
#用道路和方向进行OneHot编码
# Feature engineering
# Combine x, y and direction into a single categorical feature with 65 unique values
# which can be one-hot encoded
def place_dir(df):
return df.apply(lambda row: f"{row.x}-{row.y}-{row.direction}", axis=1).values.reshape([-1, 1])
for df in [train_orig]:
df['place_dir'] = place_dir(df)
ohe = OneHotEncoder(drop='first', sparse=False)
ohe.fit(train_orig[['place_dir']])
def engineer(df):
"""Return a new dataframe with the engineered features"""
new_df = pd.DataFrame(ohe.transform(df[['place_dir']]),
columns=ohe.categories_[0][1:],
index=df.index)
new_df['saturday'] = df.time.dt.weekday == 5
new_df['sunday'] = df.time.dt.weekday == 6
new_df['daytime'] = df.time.dt.hour * 60 + df.time.dt.minute
new_df['dayofyear'] = df.time.dt.dayofyear # to model the trend
return new_df
train = engineer(train_orig)
train['congestion'] = train_orig.congestion
features = list(train.columns)
print(list(features))
处理后的数据:
数据分割
# Split into train and test
# Use all Monday-Wednesday afternoons in August and September for validation
val_idx = ((train_orig.time.dt.month >= 8) &
(train_orig.time.dt.weekday <= 3) &
(train_orig.time.dt.hour >= 12)).values
train_idx = ~val_idx
X_tr, X_va = train.loc[train_idx, features], train.loc[val_idx, features]
y_tr, y_va = train.loc[train_idx, 'congestion'], train.loc[val_idx, 'congestion']
AdaBoost
%%time
from sklearn.ensemble import AdaBoostRegressor
regr = AdaBoostRegressor(random_state=0, n_estimators=100)
regr.fit(X_tr, y_tr)
y_pred = regr.predict(X_va)
mean_absolute_error(y_pred, y_va)
GDBT
%%time
from sklearn.ensemble import GradientBoostingRegressor
regr = GradientBoostingRegressor(random_state=0, n_estimators=100)
regr.fit(X_tr, y_tr)
y_pred = regr.predict(X_va)
mean_absolute_error(y_pred, y_va)
XGBoost
%%time
import xgboost as xgb
model = xgb.XGBRegressor(n_estimators=200)
model.fit(X_tr, y_tr)
y_pred = model.predict(X_va)
score_xgb = mean_absolute_error(y_pred, y_va)
结果:
算法 | 结果 |
---|---|
AdaBoost | 13.654161859220649 |
GBDT | 7.55620711428925 |
XGBoost | 5.880979271309312 |
XGBoost参数:
详见官网,也可以参考这篇博客:https://www.cnblogs.com/TimVerion/p/11436001.html
XGBoost做特征挖掘
XGBoost还有一个常用功能是做特征挖掘,挖掘房价预测的相关性示例:
清洗后的数据:
在挖掘特征相关性之前,需要提前做一次预测:
%%time
xgbr = xgb.XGBRegressor(verbosity=0, n_estimators=100)
xgbr.fit(X_train, y_train)
y_pred = xgbr.predict(X_test)
之后用XGBoost自带的方法就可以plot模型中各个特征相关情况
xgb.plot_importance(xgbr)
标签:实例,df,XGBoost,tr,算法,train,time,import 来源: https://www.cnblogs.com/Asp1rant/p/15997535.html