我在进行文本分类工作,在特征提取步骤之后得到了非常好的矩阵,因此我尝试使用增量学习如下所示:
import xgboost as xgbfrom sklearn.model_selection import ShuffleSplit, train_test_splitfrom sklearn.metrics import accuracy_score as accdef incremental_learning2(X, y): # 将数据分割为训练集和测试集 # 然后将训练集分成两半 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=0) X_train_1, X_train_2, y_train_1, y_train_2 = train_test_split(X_train, y_train, test_size=0.5, random_state=0) xg_train_1 = xgb.DMatrix(X_train_1, label=y_train_1) xg_train_2 = xgb.DMatrix(X_train_2, label=y_train_2) xg_test = xgb.DMatrix(X_test, label=y_test) #params = {'objective': 'reg:linear', 'verbose': False} params = {} model_1 = xgb.train(params, xg_train_1, 30) model_1.save_model('model_1.model') # ================= 训练模型的两个版本 =====================# model_2_v1 = xgb.train(params, xg_train_2, 30) model_2_v2 = xgb.train(params, xg_train_2, 30, xgb_model='model_1.model') #预测 y_pred = model_2_v2.predict(X_test) kfold = StratifiedKFold(n_splits=10, random_state=1).split(X_train, y_train) scores = [] for k, (train, test) in enumerate(kfold): model_2_v2.fit(X_train[train], y_train[train]) score = model_2_v2.score(X_train[test], y_train[test]) scores.append(score) print('Fold: %s, Class dist.: %s, Acc: %.3f' % (k+1, np.bincount(y_train[train]), score)) print('\nCV accuracy: %.3f +/- %.3f' % (np.mean(scores), np.std(scores)))
关于上述代码。我尝试进行交叉验证并预测一些实例。然而,它不起作用。我该如何修复上述代码,以便在非常大的数据集上拟合和更新GBM模型后获得交叉验证的指标和预测?
回答:
这是我想到的解决方案。首先我们导入必要的模块并定义一个简单的函数来计算均方根误差:
import numpy as npimport xgboost as xgbfrom sklearn.model_selection import train_test_split as ttsfrom sklearn.model_selection import StratifiedKFolddef rmse(a, b): return np.sqrt(((a - b) ** 2).mean())
均方根误差可以以不同的方式计算(查看此线程以获取详细信息),但为了清晰起见,我选择了一个明确的公式。
这是您的函数的一个快速且粗糙的版本。我尝试保持您的代码结构不变,但为了可读性,我进行了一些重构。
def incremental_learning2(X, y, n_splits=10, params = {}): # 初始化分数数组 sc_1, sc_2_v1, sc_2_v2 = (np.zeros(n_splits) for i in range(3)) # 创建交叉验证器 kfold = StratifiedKFold(n_splits=n_splits, random_state=0).split(X, y) # 迭代折叠 for k, (train, test) in enumerate(kfold): # 分割数据 X_test, y_test = X[test], y[test] splits = tts(X[train], y[train], test_size=0.5, random_state=0) X_train_1, X_train_2, y_train_1, y_train_2 = splits # 创建数据矩阵 xg_train_1 = xgb.DMatrix(X_train_1, label=y_train_1) xg_train_2 = xgb.DMatrix(X_train_2, label=y_train_2) xg_test = xgb.DMatrix(X_test, label=y_test) # 拟合模型 model_1 = xgb.train(params, xg_train_1, 30) model_1.save_model('model_1.model') model_2_v1 = xgb.train(params, xg_train_2, 30) model_2_v2 = xgb.train(params, xg_train_2, 30, xgb_model='model_1.model') # 进行预测和计算分数 preds = (m.predict(xg_test) for m in [model_1, model_2_v1, model_2_v2]) sc_1[k], sc_2_v1[k], sc_2_v2[k] = (rmse(p, y_test) for p in preds) # 返回分数 return sc_1, sc_2_v1, sc_2_v2
我还改进了输出格式,以表格形式显示结果。此功能在单独的函数中实现:
def display_results(a, b, c): def hline(): print('-'*50) print('交叉验证均方根误差\n') print('折叠\tmodel_v1\tmodel_2_v1\tmodel_2_v2') hline() for k, (ak, bk, ck) in enumerate(zip(a, b, c)): print('%s\t%.3f\t\t%.3f\t\t%.3f' % (k+1, ak, bk, ck)) hline() print('平均\t%.3f\t\t%.3f\t\t%.3f' % tuple(np.mean(s) for s in [a, b, c])) print('标准差\t%.3f\t\t%.3f\t\t%.3f' % tuple(np.std(s) for s in [a, b, c]))
演示
由于您没有分享您的数据集,我不得不生成模拟数据来测试我的代码。
from sklearn.datasets import make_blobsX, y = make_blobs(n_samples=500000, centers=50, random_state=0)scores_1, scores_2_v1, scores2_v2 = incremental_learning2(X, y)display_results(scores_1, scores_2_v1, scores2_v2)
上述代码运行无误,输出如下所示:
交叉验证均方根误差折叠 model_v1 model_2_v1 model_2_v2--------------------------------------------------1 9.127 9.136 9.1162 9.168 9.155 9.1283 9.117 9.095 9.0804 9.107 9.113 9.0895 9.122 9.126 9.1096 9.096 9.099 9.0847 9.148 9.163 9.1458 9.089 9.090 9.0699 9.128 9.122 9.10810 9.185 9.162 9.160--------------------------------------------------平均 9.129 9.126 9.109标准差 0.029 0.026 0.028
备注
- 为了比较目的,我也对
model_1
进行了交叉验证。 - 在示例运行中,
model_1
和model_2_v1
的准确性大致相同,而model_2_v2
表现得稍好,正如人们合理预期的那样。 - 我尝试了不同的大数据集大小(
n_samples
)和类别数(centers
),有趣的是,当这些参数的值降低时,model_2_v2
是三者中准确性最低的。 - 希望通过使用不同的配置,即正确设置命名的函数参数
params
,应该可以使事情按预期进行。