【问题标题】:SkLearn - Using RegressorChain with ColumnTransformer in Pipelines?SkLearn - 在管道中使用 RegressorChain 和 ColumnTransformer?
【发布时间】:2021-09-26 13:21:12
【问题描述】:

我在使用 sklearn 的 RegressorChain (https://scikit-learn.org/stable/modules/generated/sklearn.multioutput.RegressorChain.html) 时遇到问题,不幸的是,似乎没有很多关于此的文档/示例。

文档间接说明(通过set_params 方法)它可以与管道一起使用。我的管道有:

ct = ColumnTransformer(
    transformers=[
        ('scaler', MinMaxScaler(), numerical_columns),
        ('onehot', OneHotEncoder(), ['day_of_week']),
    ],
    remainder='passthrough'
)

cv = TimeSeriesSplit(n_splits = groups.nunique()) #groups by date

pipeline = make_pipeline(ct, lgb.LGBMRegressor(random_state=42))

target_transform_output = TransformedTargetRegressor(regressor=pipeline, transformer=PowerTransformer())

然后我做:

chain_regressor = RegressorChain(base_estimator=target_transform_output , order=[1,0,2])
chain_regressor.fit(X, y)

上面X和y都是pandas Dataframe,y有3个目标列。

当我运行代码时,我得到一个由fit() 调用引起的python 堆栈跟踪,在执行all_columns = X.columns 时从__init.py__ 开始在_get_column_indices(X, key) 中。错误是:

AttributeError: 'numpy.ndarray' object has no attribute 'columns'

在堆栈跟踪的末尾进一步向下:

ValueError: Specifying the columns using strings is only supported for pandas DataFrames

我认为这是因为 ColumnTransformer 返回 ndarrays,这是一个众所周知的问题。这是否意味着RegressorChain 不能与ColumnTransformer 一起使用?

在此之后,我从管道中删除了列转换器步骤并再次尝试,没有 ColumnTransformer 一切正常(即使是 TransformedTargetRegressor)。

感谢任何帮助、想法或解决方法。

【问题讨论】:

  • 为什么不把你的 numpy 数组转换成 pandas 数据帧?
  • 嗨@wundermahn。正如我上面所说:“X 和 y 都是 pandas 数据帧,并且 y 有 3 个目标列。”我没有在我的代码中的任何地方使用 ndarrays。
  • 那么你是如何得到一个 numpy 数组的错误的呢?正如你上面所说,当我运行代码时,我得到一个由 fit() 引起的 python 堆栈跟踪...AttributeError: 'numpy.ndarray' object has no attribute 'columns'
  • ColumnTransformer 输出 ndarrays,即使你给它 Pandas Dataframes。 sklearn 的众所周知的问题,自 2015 年以来报告。我想了解的是是否有任何解决方法(或发现我正在犯的错误),以便它们可以与 RegressorChain 一起使用。检查:github.com/scikit-learn/scikit-learn/issues/5523,例如。
  • 正是我在第一条评论中所说的。为什么不将 ColumnTransformer 的输出存储到数据框中?

标签: pandas scikit-learn


【解决方案1】:

你的问题搞错了:不是ColumnTransformer 输出一个数组而RegressorChain 期望一个数据帧;相反,RegressorChain 在调用管道之前会将您的输入转换为数组,因此您的 ColumnTransformer 不会将数据框作为输入,也无法使用您的列名规范。

您可以只在ColumnTransformer 中按索引或可调用指定列。但我认为在这种情况下,你有两个不幸的副作用:

  1. 对于每个目标,您都在重新编码 day_of_week 并重新缩放每个自变量(没有错,只是有点浪费),并且
  2. 您永远不会缩放目标,即使它们被用作“后期”目标回归的自变量(对于像 lightGBM 这样的基于树的模型来说并没有错[事实上,对于 LGBM,为什么还要进行缩放?] ,但其他模型可能会因无法缩放这些模型而受到影响。

(1) 可以通过预处理作为管道步骤来修复之前 RegressorChain。 (2) 可以通过将缩放器的列规范更改为可调用来修复,下面使用帮助器make_column_selector。对 (2) 进行修复确实最终会在每一步重新计算缩放比例(再次伤害 (1)),但我认为最终这是一个更大的问题(如果你想在某些时候使用树模型以外的东西观点)。 所以我建议改为:

encoder = ColumnTransformer(
    transformers=[
        ('onehot', OneHotEncoder(), ['day_of_week']),
    ],
    remainder='passthrough',
)

scale_nums = ColumnTransformer(
    transformers=[
        ('scaler', MinMaxScaler(), make_column_selector(dtype_include=np.number)),
    ],
    remainder='passthrough',
)

modeling_pipe = make_pipeline(scale_nums, lgb.LGBMRegressor(random_state=42))

target_transform_output = TransformedTargetRegressor(
    regressor=modeling_pipe,
    transformer=PowerTransformer(),
)

final_pipeline = make_pipeline(encoder, target_transform_output)

【讨论】:

    猜你喜欢
    • 2020-03-08
    • 1970-01-01
    • 2019-06-15
    • 2020-12-03
    • 2014-11-07
    • 2021-03-05
    • 2019-06-29
    • 2015-03-26
    • 1970-01-01
    相关资源
    最近更新 更多