将流水线 XGBoost 0.90 模型转换为 XGBoost 1.0+

Convert pipelined XGBoost 0.90 model to XGBoost 1.0+

假设我有一个像这样设置的 XGBoost 0.90 模型,使用 scikit-learn 管道进行一些预处理。我想升级到 XGBoost 1.0+ 并且仍然可以使用这个模型,而不必改装它。

import pandas as pd
import numpy as np
from sklearn_pandas import DataFrameMapper
from xgboost import XGBRegressor
from sklearn.preprocessing import FunctionTransformer, MinMaxScaler
from sklearn.pipeline import Pipeline


df = pd.DataFrame({
    'a': [0.0, 45.0, 90.0, 135.0, 180.0, np.nan],
    'b': [180.0, 135.0, 90.0, 45.0, 0.0, np.nan],
    'y': [1.0, 3.0, 4.0 ,5.0 ,6.0 ,0.0]
})

pipeline = Pipeline([
    ('mapper', DataFrameMapper([
        (['a', 'b'], [MinMaxScaler(feature_range=(0, 2*np.pi)), FunctionTransformer(np.cos)], ),
        (['a', 'b'], [MinMaxScaler(feature_range=(0, 2*np.pi)), FunctionTransformer(np.sin)], )        
    ])),
    ('regressor', XGBRegressor())
])

pipeline.fit(df[['a', 'b']], df['y'])

如果我在安装 XGBoost 0.90 时对管道进行 pickle,则在随后安装 XGBoost 1.0+ 时无法加载它。 XGBoost 文档建议我应该使用他们提供的脚本转换 0.90 pickle:

https://xgboost.readthedocs.io/en/latest/tutorials/saving_model.html#loading-pickled-file-from-different-version-of-xgboost

脚本可在此处获得:

https://github.com/dmlc/xgboost/blob/master/doc/python/convert_090to100.py

但是,此脚本仅适用于 XGBoost Booster 对象。所以我尝试了以下方法:

现在我有点卡住了。我如何使用原始 0.90 pickle 中的映射器和从导出文件加载的助推器重新组装我的管道?

更新

这里有一些关于我如何保存和重新加载助推器的详细信息:

首先,我从管道中提取了最终的估计器:

joblib.dump(pipeline._final_estimator, './final_estimator.pkl')

接下来,我运行泡菜上的转换脚本:

python3 convert_090to100.py --old-pickle final_estimator.pkl

然后我导入了脚本生成的文件:

final_estimator_reloaded = XGBRegressor()
final_estimator_reloaded.load_model('./xgboost_native_model_from_final_estimator.pkl-0.bin')

然后我使用这个重新加载的模型生成了一个管道并尝试用它生成预测:

rebuilt_pipeline = Pipeline([
    ('mapper', pipeline[0]),
    ('regressor', final_estimator_reloaded)
])

rebuilt_pipeline.predict(df)

进一步更新:这毕竟有效。

您可以通过索引任意提取流水线步骤,最终估算器为Pipeline._final_estimator_ 属性.

在您当前的基础上构建新的“预装”管道:

mapper = pipeline[0]
print(mapper)

regressor = pipeline._final_estimator
print(regressor)

pipeline2 = Pipeline([
  ("mapper", mapper),
  ("regressor", regressor)
])
print(pipeline2.predict(df[["a", "b"]]))