在分类列上训练 xgboost 时遇到问题
Posted
技术标签:
【中文标题】在分类列上训练 xgboost 时遇到问题【英文标题】:Trouble training xgboost on categorical column 【发布时间】:2019-09-28 23:49:14 【问题描述】:我正在尝试运行 Python 笔记本 (link)。在 [446] 下面的行:作者训练 XGBoost
,我收到一个错误
ValueError:数据的 DataFrame.dtypes 必须是 int、float 或 bool。 没想到StateHoliday、Assortment字段中的数据类型
# XGB with xgboost library
dtrain = xgb.DMatrix(X_train[predictors], y_train)
dtest = xgb.DMatrix(X_test[predictors], y_test)
watchlist = [(dtrain, 'train'), (dtest, 'test')]
xgb_model = xgb.train(params, dtrain, 300, evals = watchlist,
early_stopping_rounds = 50, feval = rmspe_xg, verbose_eval = True)
这是用于测试的最少代码
import pickle
import numpy as np
import xgboost as xgb
from sklearn.model_selection import train_test_split
with open('train_store', 'rb') as f:
train_store = pickle.load(f)
train_store.shape
predictors = ['Store', 'DayOfWeek', 'Open', 'Promo', 'StateHoliday', 'SchoolHoliday', 'Year', 'Month', 'Day',
'WeekOfYear', 'StoreType', 'Assortment', 'CompetitionDistance', 'CompetitionOpenSinceMonth',
'CompetitionOpenSinceYear', 'Promo2', 'Promo2SinceWeek', 'Promo2SinceYear', 'CompetitionOpen',
'PromoOpen']
y = np.log(train_store.Sales) # log transformation of Sales
X = train_store
# split the data into train/test set
X_train, X_test, y_train, y_test = train_test_split(X, y,
test_size = 0.3, # 30% for the evaluation set
random_state = 42)
# base parameters
params =
'booster': 'gbtree',
'objective': 'reg:linear', # regression task
'subsample': 0.8, # 80% of data to grow trees and prevent overfitting
'colsample_bytree': 0.85, # 85% of features used
'eta': 0.1,
'max_depth': 10,
'seed': 42 # for reproducible results
num_round = 60 # default 300
dtrain = xgb.DMatrix(X_train[predictors], y_train)
dtest = xgb.DMatrix(X_test[predictors], y_test)
watchlist = [(dtrain, 'train'), (dtest, 'test')]
xgb_model = xgb.train(params, dtrain, num_round, evals = watchlist,
early_stopping_rounds = 50, feval = rmspe_xg, verbose_eval = True)
train_store 数据文件链接:Link 1
【问题讨论】:
这不是最小的,就像在 MCVE 中一样。你的意思是StateHoliday
列是分类的吗?如果是,请在问题中这样说。
【参考方案1】:
我在做罗斯曼销售预测项目时遇到了完全相同的问题。 似乎新版本的 xgboost 不接受 StateHoliday、Assortment 和 StoreType 的数据类型。 您可以使用以下方法检查 Mykhailo Lisovyi 建议的数据类型
print(test_train.dtypes)
你需要在这里用你的 X_train 替换 test_train
你可能会得到
DayOfWeek int64
Promo int64
StateHoliday int64
SchoolHoliday int64
StoreType object
Assortment object
CompetitionDistance float64
CompetitionOpenSinceMonth float64
CompetitionOpenSinceYear float64
Promo2 int64
Promo2SinceWeek float64
Promo2SinceYear float64
Year int64
Month int64
Day int64
object 类型引发的错误。您可以将它们转换为
from sklearn import preprocessing
lbl = preprocessing.LabelEncoder()
test_train['StoreType'] = lbl.fit_transform(test_train['StoreType'].astype(str))
test_train['Assortment'] = lbl.fit_transform(test_train['Assortment'].astype(str))
完成这些步骤后一切都会顺利。
【讨论】:
【参考方案2】:试试这个
train_store['StateHoliday'] = pd.to_numeric(train_store['StateHoliday'])
train_store['Assortment'] = pd.to_numeric(train_store['Assortment'])
【讨论】:
如果您想在生产中使用经过训练的模型,并且将来需要对测试样本应用相同的编码,则必须使用另一种编码方式,例如scikit智元在他的回答中展示了变形金刚,这样变形金刚可以和模型一起保存。对新数据运行 pd.to_numeric() 可能会导致与您最初在训练期间使用的映射不同!【参考方案3】:正如错误消息所暗示的,xgboost
很不高兴,因为您尝试为其提供未知类型。它说它不能处理分类或日期时间特征。检查StateHoliday, Assortment
特征的类型并以某种方式将它们编码为数字(例如 One-Hot Encoding、标签编码(适用于基于树的模型)或目标编码)
【讨论】:
我检查了数据类型是int
您能否从完整的堆栈跟踪中检查哪个命令导致ValueError
并将该数据帧的.dtypes
转储添加到原始问题中?问题的根源在于 xgboost 不支持的类型。代码中列出了支持的类型:github.com/dmlc/xgboost/blob/…【参考方案4】:
H2O 包中的 XGBoost 版本可以处理分类变量(但不能太多!),但 XGBoost 作为其自己的包似乎不能。
我用 pandas 数据框试过这个,但 xgboost 不喜欢它
categoricals = ['StoreType', ] . # etc.
pdf[categorical] = pdf[categorical].astype('category')
要将 H2O 用于分类,您必须先将字符串转换为分类:
h2odf[categoricals] = h2odf[categoricals].asfactor()
还要注意,h2o 有自己的数据框,与 pandas 不同。
【讨论】:
这是不准确的。 XGBoost 可以自己处理分类。 xgboost.readthedocs.io/en/latest/tutorials/…以上是关于在分类列上训练 xgboost 时遇到问题的主要内容,如果未能解决你的问题,请参考以下文章
R语言构建xgboost模型并评估模型(测试集训练集每一轮):误分类率指标(misclassification rate)logloss