XGBoost算法-代码实现和网格调参

目录

导包

特征工程

基本模型

超参数优化


导包

import pandas as pd
import numpy as np
import xgboost as xgb
import pickle
import sys
import matplotlib.pyplot as plt
from sklearn.metrics import make_scorer
from sklearn.metrics import mean_absolute_error
from sklearn.preprocessing import LabelEncoder, LabelBinarizer
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import KFold, train_test_split

from xgboost import XGBRegressor

import warnings

warnings.filterwarnings('ignore')
%matplotlib inline

%config InlineBackend.figure_format = 'retina'

特征工程

# 测试集特征
train = pd.read_csv('allstate-claims-severity/train.csv')
train['log_loss'] = np.log(train['loss'])
features = [x for x in train.columns if x not in ['id','loss','log_loss']]
cat_features =[x for x in train.select_dtypes(include = ['object']) if x not in ['id','loss','log_loss']]
num_features =[x for x in train.select_dtypes(exclude = ['object']) if x not in ['id','loss','log_loss']]
print('训练集-离散特征Categorical: {} features'.format(len(cat_features)))
print('训练集-连续值特征Numerical:{} features'.format(len(num_features)))

# 得到训练集x和y
train_x = train[features]
train_y = train['log_loss']

# 离散特征单独处理成pandas的category类型
for c in range(len(cat_features)):
    train_x[cat_features[c]] = train_x[cat_features[c]].astype('category').cat.codes
print('Xtrain:',train_x.shape) # Xtrain: (188318, 130)
print('ytrain:',train_y.shape) # ytrain: (188318,)

# 截止到这个位置,训练集已经可用
train_x
train_y

基本模型

import pandas as pd
import numpy as np
import xgboost as xgb
import matplotlib.pyplot as plt
from sklearn.metrics import mean_absolute_error
import warnings

warnings.filterwarnings('ignore')  # 忽略警告信息,以便输出更清晰

# 自定义评估函数,用于计算平均绝对误差(MAE)
def xg_eval_mae(yhat, dtrain):
    y = dtrain.get_label()
    # 对预测值和真实值进行指数变换,然后计算MAE
    return 'mae', mean_absolute_error(np.exp(y), np.exp(yhat))

# 定义XGBoost回归模型类
class XGBoostRegressor(object):
    def __init__(self, **kwargs):
        # 初始化模型参数,包括用户自定义参数和默认参数
        self.params = kwargs
        self.params.update({
            'verbosity': 0,  # 设置日志等级
            'objective': 'reg:squarederror',  # 设置目标函数为平方误差
            'seed': 0,  # 设置随机种子
            'num_boost_round': 100  # 设置boosting round的数量
        })
        self.bst = None  # 初始化模型对象为None

    def fit(self, x_train, y_train):
        # 训练模型
        dtrain = xgb.DMatrix(x_train, label=y_train)
        try:
            self.bst = xgb.train(
                params=self.params,  # 模型参数
                dtrain=dtrain,  # 训练数据
                num_boost_round=self.params['num_boost_round'],  # boosting round数量
                feval=xg_eval_mae,  # 自定义评估函数
                maximize=False  # 评估函数的最大化标志
            )
        except Exception as e:
            print("Error during training:", e)
            self.bst = None

    def predict(self, x_pred):
        # 预测函数
        if self.bst is None:
            raise ValueError("Model not trained. Call 'fit' before 'predict'.")
        dpred = xgb.DMatrix(x_pred)
        return self.bst.predict(dpred)

    def kfold(self, x_train, y_train, nfold=5):
        # 交叉验证函数
        dtrain = xgb.DMatrix(x_train, label=y_train)
        cv_results = xgb.cv(
            params=self.params,  # 模型参数
            dtrain=dtrain,  # 训练数据
            num_boost_round=self.params['num_boost_round'],  # boosting round数量
            nfold=nfold,  # 交叉验证的折数
            feval=xg_eval_mae,  # 自定义评估函数
            maximize=False,  # 评估函数的最大化标志
            early_stopping_rounds=10,  # 提前停止的轮数
            metrics={'mae'}  # 评估指标
        )
        return pd.DataFrame(cv_results)

    def plot_feature_importances(self):
        # 绘制特征重要性
        if self.bst is None:
            raise ValueError("Model not trained. Call 'fit' before plotting feature importances.")
        feat_imp = pd.Series(self.bst.get_score(importance_type='weight')).sort_values(ascending=False)
        feat_imp.plot(kind='bar', title='Feature Importances')
        plt.ylabel('Feature Importance Score')
        plt.show()

    def get_params(self, deep=True):
        # 获取模型参数
        return self.params

    def set_params(self, **params):
        # 设置模型参数
        self.params.update(params)
        return self

    def save_model(self, filepath):
        # 保存模型到本地文件
        if self.bst is not None:
            self.bst.save_model(filepath)
        else:
            raise ValueError("Model not trained. Call 'fit' before saving the model.")

# 特征工程
train = pd.read_csv('allstate-claims-severity/train.csv')
train['log_loss'] = np.log(train['loss'])  # 对target进行对数变换
features = [x for x in train.columns if x not in ['id', 'loss', 'log_loss']]  # 选择特征列
cat_features = [x for x in train.select_dtypes(include=['object']) if x not in ['id', 'loss', 'log_loss']]  # 选择类别特征
num_features = [x for x in train.select_dtypes(exclude=['object']) if x not in ['id', 'loss', 'log_loss']]  # 选择数值特征
print('训练集-离散特征Categorical: {} features'.format(len(cat_features)))
print('训练集-连续值特征Numerical: {} features'.format(len(num_features)))
train_x = train[features]
train_y = train['log_loss']

# 检查loss列是否为非负
if any(train['loss'] < 0):
    raise ValueError("Column 'loss' must be non-negative for log transformation.")

# 离散特征单独处理成pandas的category类型
for c in range(len(cat_features)):
    train_x[cat_features[c]] = train_x[cat_features[c]].astype('category').cat.codes

# 模型训练
bst = XGBoostRegressor(eta=0.1,
                       colsample_bytree=0.5,
                       subsample=0.5,
                       max_depth=5,
                       min_child_weight=3,
                       num_boost_round=100)
kfold_results = bst.kfold(train_x, train_y, nfold=5)

# 绘制MAE结果
kfold_results.mean(axis=1).plot(title='K-Fold MAE')
plt.xlabel('Boosting Round')
plt.ylabel('MAE')
plt.show()

# 再次训练模型
bst.fit(train_x, train_y)

# 保存模型到本地
model_filename = 'xgboost_model.json'
bst.save_model(model_filename)

test = pd.read_csv('allstate-claims-severity/test.csv')
test_x = test[features]

# 将类别数据的类别用数字替换
for c in range(len(cat_features)):
    test_x[cat_features[c]] = test_x[cat_features[c]].astype('category').cat.codes

# 预测命令:
test_y = bst.predict(test_x)

# 保存预测结果
test['predicted_loss'] = np.exp(test_y)
test[['id', 'predicted_loss']].to_csv('submission.csv', index=False)

bst.get_params()

在XGBoost中,这些超参数控制着模型的训练过程和行为。下面是每个超参数的含义:

  1. eta (学习率):
    • 控制每一步迭代中权重调整的幅度。较小的值意味着模型需要更多的迭代次数来训练,但可能会获得更好的性能和泛化能力。
  1. colsample_bytree (每棵树的特征采样比率):
    • 每棵树在训练时用到的特征数量的比例。值在0到1之间,用于随机特征选择,以增加模型的多样性并防止过拟合。
  1. subsample (训练样本的采样比率):
    • 训练每棵树时使用的样本比例。值在0到1之间,同样用于增加模型的多样性和防止过拟合。
  1. max_depth (树的最大深度):
    • 树的最大深度。树越深,模型越复杂,可能会有更好的性能,但也更容易过拟合。
  1. min_child_weight (子节点最小权重):
    • 决定最小数据权重和,需要在叶子节点上观察到进一步分裂。增加这个值可以防止模型学习到过于复杂的模式。
  1. num_boost_round (提升轮数):
    • 总共要执行的提升(boosting)轮数。更多的轮数可能会提高模型的性能,但也可能增加过拟合的风险。
  1. verbosity (日志等级):
    • 控制XGBoost打印的输出信息的详细程度。等级越高,打印的信息越少。
  1. objective (目标函数):
    • 指定学习任务和相应的学习目标或预测类型。在这个例子中,'reg:squarederror' 表示回归任务,使用平方误差作为损失函数。
  1. seed (随机种子):
    • 控制随机数生成器的种子。用于结果的可重复性。

这些超参数的合理设置对于模型的性能至关重要。通常,需要通过交叉验证等方法来调整这些参数,以找到最佳的模型配置。

{'eta': 0.1,
 'colsample_bytree': 0.5,
 'subsample': 0.5,
 'max_depth': 5,
 'min_child_weight': 3,
 'num_boost_round': 100,
 'verbosity': 0,
 'objective': 'reg:squarederror',
 'seed': 0}

超参数优化

利用GridSearchCV算法,找出最合适的num_boost_round和学习率eta超参数

import pandas as pd
import numpy as np
import xgboost as xgb
import matplotlib.pyplot as plt
from sklearn.model_selection import GridSearchCV, train_test_split
from sklearn.metrics import mean_absolute_error
import warnings

warnings.filterwarnings('ignore')  # 忽略警告信息,以便输出更清晰

# 读取数据并进行预处理
train = pd.read_csv('allstate-claims-severity/train.csv')
train['log_loss'] = np.log(train['loss'])  # 对target进行对数变换
features = [x for x in train.columns
            if x not in ['id', 'loss', 'log_loss']]  # 选择特征列
cat_features = [
    x for x in train.select_dtypes(include=['object'])
    if x not in ['id', 'loss', 'log_loss']
]  # 选择类别特征
for c in cat_features:
    train[c] = train[c].astype('category').cat.codes  # 将类别特征转换为数值

train_x = train[features]
train_y = train['log_loss']

# 划分训练集和验证集
x_train, x_val, y_train, y_val = train_test_split(train_x,
                                                  train_y,
                                                  test_size=0.2,
                                                  random_state=0)

# 设置XGBoost模型和参数网格
xgb_reg = xgb.XGBRegressor(colsample_bytree=0.5,
                           subsample=0.5,
                           max_depth=5,
                           min_child_weight=3,
                           objective='reg:squarederror',
                           seed=0)

# 设置GridSearchCV
param_grid = {
    'n_estimators': [100, 200, 300, 400, 500],  # 尝试不同的num_boost_round值
    'eta': [0.01, 0.05, 0.1, 0.2]  # 尝试不同的学习率
}
grid_search = GridSearchCV(estimator=xgb_reg,
                           param_grid=param_grid,
                           scoring='neg_mean_absolute_error',
                           cv=3,
                           verbose=1)
grid_search.fit(x_train, y_train)

# 打印最佳参数和得分
print("Best parameters:", grid_search.best_params_)
print("Best MAE:", -grid_search.best_score_)

# 打印每个参数组合及其得分
results = grid_search.cv_results_
for mean_score, params in zip(results['mean_test_score'], results['params']):
    print(np.sqrt(-mean_score), params)  # 打印MAE而不是负MAE

# 使用最佳参数再次训练模型
best_params = grid_search.best_params_
best_xgb_reg = xgb.XGBRegressor(n_estimators=best_params['n_estimators'],
                                eta=best_params['eta'],
                                colsample_bytree=0.5,
                                subsample=0.5,
                                max_depth=5,
                                min_child_weight=3,
                                objective='reg:squarederror',
                                seed=0)
best_xgb_reg.fit(x_train, y_train)

# 预测验证集
predictions = best_xgb_reg.predict(x_val)
mae = mean_absolute_error(y_val, predictions)
print("Validation MAE:", mae)

# 绘制验证集的MAE结果
plt.figure()
plt.plot(predictions, label='Predictions')
plt.plot(y_val.values, label='True Values')
plt.legend()
plt.title('XGBoost Predictions vs True Values')
plt.xlabel('Sample Index')
plt.ylabel('Log Loss')
plt.show()

这段执行结果提供了通过GridSearchCV进行的模型超参数优化和验证的细节。以下是对这些输出的解释:

  1. 交叉验证过程:
    • "Fitting 3 folds for each of 2 candidates, totalling 6 fits" 表示GridSearchCV使用了3折交叉验证来评估两个不同的参数组合(在这个例子中是n_estimators的值)。总共进行了6次拟合(3折 x 2参数值)。
  1. 最佳参数和得分:
    • "Best parameters: {'n_estimators': 200}" 表示在测试的参数组合中,当n_estimators(即提升树的数量)设置为200时,模型的性能最佳。
    • "Best MAE: 0.4214897722016709" 显示了使用最佳参数时的平均绝对误差(MAE)。这是在交叉验证过程中得到的最优结果。
  1. 每个参数组合的得分:
    • "0.6529385343493455 {'n_estimators': 100}" 和 "0.6492224366129615 {'n_estimators': 200}" 显示了每个参数组合的平均测试分数。这里显示的分数是负MAE,因为GridSearchCV默认是寻找最小化的目标,所以使用负数表示。正值0.6529385343493455和0.6492224366129615实际上是MAE值,其中较小的值(对应n_estimators为200)表示更好的性能。
  1. 验证集上的MAE:
    • "Validation MAE: 0.41929878566038986" 表示在独立的验证集上,使用最佳参数(n_estimators=200)训练的模型的平均绝对误差。这个值用于最终评估模型在未知数据上的性能。

理解关键点:

  • 较小的MAE值 表示模型预测与实际值之间的误差较小,即模型的预测性能较好。
  • 交叉验证 是一种重要的技术,用于评估不同参数设置下模型的稳健性和泛化能力。
  • GridSearchCV 提供了一个系统的方法来尝试多种参数组合,找到最优的模型配置。

在实际应用中,这些信息帮助我们理解模型在不同配置下的表现,并选择最佳的模型参数进行最终的模型部署和预测。

XGBoost是一个强大的梯度提升库,常用于机器学习中的分类回归任务。在R语言中,使用XGBoost可以通过`xgboost`包来实现。以下是创建一个简单的XGBoost预测模型的基本步骤: ```R # 首先,安装并加载xgboost包(如果尚未安装) install.packages("xgboost") library(xgboost) # 假设你已经有了一个数据集df,其中包含特征变量X目标变量Y # 数据预处理(包括分列、缺失值处理、编码等) data <- df[, c("X1", "X2", "X3")] # 选择特征列 label <- df$Y # 划分训练集测试集 set.seed(123) # 设置随机种子以保证结果可重复 train_index <- sample(1:nrow(data), 0.7 * nrow(data)) # 70%用于训练 train_data <- data[train_index, ] test_data <- data[-train_index, ] train_label <- label[train_index] test_label <- label[-train_index] # 创建DMatrix对象,这是XGBoost的数据结构 dtrain <- xgb.DMatrix(train_data, label = train_label) dtest <- xgb.DMatrix(test_data, label = test_label) # 定义数(这里是一个基本配置,可能需要调整) params <- list( booster = "gbtree", # 使用GBDT算法 objective = "binary:logistic", # 对于二分类任务 max_depth = 3, # 树的最大深度 eta = 0.3, # 学习率 nrounds = 100 # 迭代轮数 ) # 训练模型 model <- xgb.train(params, dtrain, num_boost_round = nrounds) # 使用模型进行预测 predictions <- predict(model, dtest) # 评估模型性能(例如,计算准确率) accuracy <- mean(predictions == test_label) cat(paste("Accuracy: ", round(accuracy * 100, 2), "%\n")) #
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值