如何在 Python 中转换回归的目标变量

数据准备是应用机器学习的一个重要部分。

正确地准备训练数据可以决定平庸和非凡结果的差异,即使对于非常简单的线性算法也是如此。

执行数据准备操作,如缩放,对于输入变量相对简单,并且已经通过 scikit-learn 的 Pipeline 类在 Python 中例行化。

在需要预测数值的回归预测建模问题中,对目标变量进行缩放和其他数据转换也可能至关重要。这可以在 Python 中使用 TransformedTargetRegressor 类来实现。

在本教程中,您将学习如何使用 TransformedTargetRegressor 来缩放和转换 scikit-learn Python 机器学习库中的回归目标变量。

完成本教程后,您将了解:

  • 缩放输入和目标数据对机器学习的重要性。
  • 将数据转换应用于目标变量的两种方法。
  • 如何在实际回归数据集上使用 TransformedTargetRegressor。

通过我的新书《机器学习数据准备》开始您的项目,其中包括分步教程和所有示例的Python 源代码文件。

让我们开始吧。

How to Transform Target Variables for Regression With Scikit-Learn

如何使用 Scikit-Learn 转换回归目标变量
照片由 Don Henise 拍摄,保留部分权利。

教程概述

本教程分为三个部分;它们是:

  1. 数据缩放的重要性
  2. 如何缩放目标变量
  3. 使用 TransformedTargetRegressor 的示例

数据缩放的重要性

数据中变量的尺度各不相同是很常见的。

例如,一个变量可能是英尺,另一个是米,等等。

如果所有变量都被缩放到相同的范围,例如将所有变量缩放到 0 到 1 之间的值,称为归一化,那么一些机器学习算法会表现得更好。

这会影响使用输入加权和的算法,如线性模型和神经网络,以及使用距离度量的模型,如支持向量机和 K 最近邻。

因此,缩放输入数据是一个好习惯,甚至可以尝试其他数据转换,例如使用幂转换使数据更正态(更好地拟合高斯概率分布)。

这也适用于输出变量,称为目标变量,例如在建模回归预测问题时预测的数值。

对于回归问题,通常希望同时缩放或转换输入和目标变量。

缩放输入变量很简单。在 scikit-learn 中,您可以手动使用 scale 对象,或者使用更方便的 Pipeline,它允许您在模型之前将一系列数据转换对象链接在一起。

Pipeline 将在训练数据上为您拟合 scale 对象,并将转换应用于新数据,例如在使用模型进行预测时。

例如

挑战在于,scikit-learn 中用于缩放目标变量的等效机制是什么?

想开始学习数据准备吗?

立即参加我为期7天的免费电子邮件速成课程(附示例代码)。

点击注册,同时获得该课程的免费PDF电子书版本。

如何缩放目标变量

您可以通过两种方式缩放目标变量。

第一种是手动管理转换,第二种是使用一种新的自动方法来管理转换。

  1. 手动转换目标变量。
  2. 自动转换目标变量。

1. 手动转换目标变量

手动管理目标变量的缩放涉及手动创建并应用缩放对象到数据。

它包括以下步骤:

  1. 创建转换对象,例如 MinMaxScaler。
  2. 在训练数据集上拟合转换。
  3. 将转换应用于训练和测试数据集。
  4. 对任何预测进行逆转换。

例如,如果我们想对目标变量进行归一化,我们将首先定义和训练一个MinMaxScaler 对象

然后,我们将转换训练和测试目标变量数据。

然后,我们将拟合模型并使用模型进行预测。

在可以使用预测或使用误差度量对其进行评估之前,我们必须进行逆转换。

这很麻烦,因为它意味着您无法使用 scikit-learn 中的便捷函数,例如cross_val_score(),来快速评估模型。

2. 自动转换目标变量

另一种方法是自动管理转换和逆转换。

这可以通过使用TransformedTargetRegressor 对象来实现,该对象封装了给定的模型和缩放对象。

它将使用与拟合模型相同的训练数据来准备目标变量的转换,然后在使用调用 predict() 的任何新数据时应用该逆转换,从而以正确的尺度返回预测。

要使用 TransformedTargetRegressor,它通过指定模型和要应用于目标的转换对象来定义;例如:

之后,TransformedTargetRegressor 实例可以像任何其他模型一样通过调用 fit() 函数进行拟合,并可以通过调用 predict() 函数进行预测。

这要容易得多,而且允许您使用诸如 cross_val_score() 等有用的函数来评估模型。

现在我们熟悉了 TransformedTargetRegressor,让我们来看一个在实际数据集上使用它的示例。

使用 TransformedTargetRegressor 的示例

在本节中,我们将演示如何在实际数据集上使用 TransformedTargetRegressor。

我们将使用波士顿住房回归问题,该问题有 13 个输入和一个数值目标,需要学习郊区特征与房价之间的关系。

数据集可在此处下载

下载数据集并将其保存在当前工作目录中,名称为“housing.csv”。

查看数据集中,您应该会看到所有变量都是数字的。

您可以在此处了解有关此数据集及其列含义的更多信息。

我们可以确认数据集可以正确加载为 NumPy 数组,并将其分割为输入和输出变量。

完整的示例如下所示。

运行示例会打印数据集的输入和输出部分的形状,显示 13 个输入变量、1 个输出变量以及 506 行数据。

现在我们可以准备一个使用 TransformedTargetRegressor 的示例。

该问题上的朴素回归模型预测目标均值可以获得约 6.659 的平均绝对误差 (MAE)。我们的目标是做得更好。

在此示例中,我们将拟合一个HuberRegressor 对象,并使用 Pipeline 归一化输入变量。

接下来,我们将定义一个 TransformedTargetRegressor 实例,并将 regressor 设置为 pipeline,将 transformer 设置为 MinMaxScaler 对象的实例。

我们可以使用 10 折交叉验证来评估带有输入和输出变量归一化的模型。

将所有这些结合起来,完整的示例如下所示。

运行示例将评估带有输入和输出变量归一化的模型。

注意:由于算法或评估程序的随机性,或者数值精度的差异,您的结果可能有所不同。请尝试运行示例几次并比较平均结果。

在这种情况下,我们实现了约 3.1 的 MAE,远好于朴素模型实现的约 6.6。

我们不限于使用缩放对象;例如,我们还可以探索在目标变量上使用其他数据转换,例如PowerTransformer,它可以使每个变量更像高斯分布(使用Yeo-Johnson 转换),并提高线性模型的性能。

默认情况下,PowerTransformer 在执行转换后还会对每个变量进行标准化。

下面列出了在住房数据集的输入和目标变量上使用 PowerTransformer 的完整示例。

运行示例将评估带有输入和输出变量幂转换的模型。

注意:由于算法或评估程序的随机性,或者数值精度的差异,您的结果可能有所不同。请尝试运行示例几次并比较平均结果。

在这种情况下,我们看到 MAE 进一步提高到约 2.9。

进一步阅读

如果您想深入了解,本节提供了更多关于该主题的资源。

API

数据集 (Dataset)

总结

在本教程中,您学习了如何在 scikit-learn 中使用 TransformedTargetRegressor 来缩放和转换回归目标变量。

具体来说,你学到了:

  • 缩放输入和目标数据对机器学习的重要性。
  • 将数据转换应用于目标变量的两种方法。
  • 如何在实际回归数据集上使用 TransformedTargetRegressor。

你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。

掌握现代数据准备!

Data Preparation for Machine Learning

在几分钟内准备好您的机器学习数据

...只需几行python代码

在我的新电子书中探索如何实现
机器学习数据准备

它提供**自学教程**,并附有关于以下内容的**完整工作代码**:
*特征选择*、*RFE*、*数据清洗*、*数据转换*、*缩放*、*降维*,以及更多...

将现代数据准备技术引入
您的机器学习项目


查看内容

61 条回复:如何转换 Python 中的回归目标变量

  1. Jon 2019 年 12 月 16 日上午 6:11 #

    Jason - 是否有数学依据使用测试指标对逆转换进行评估?例如,假设我有一个 log-log 模型,并且在 log 空间中得到的 r2 高于逆转换后的 r2。这是否会造成关键错误?

    • Jason Brownlee 2019 年 12 月 16 日上午 6:20 #

      仅仅是因为任何计算的误差(例如 MSE/MAE)都将具有与目标变量相同的单位,并且更容易被领域专家理解。

      如果您正在计算 r^2,我认为这不那么重要/必需。

      • Jon 2019 年 12 月 16 日上午 6:33 #

        好的,谢谢 - 我遇到一种情况,log-log 模型中的 r2 远高于使用相同函数对相同数据应用 TargetTransformer 后的 r2。只是在决定应该使用/调整哪个指标时遇到困难。

        • Jason Brownlee 2019 年 12 月 16 日下午 1:34 #

          如果 r2 是您选择的指标,请探索所有能最大化该分数的模型/转换。

  2. Shauna 2019 年 12 月 16 日下午 12:19 #

    你好 Jason。感谢这篇有用的帖子。您如何解释缩放后的变量?是否有必要将它们转换回原始尺度?最后,您如何决定是否缩放目标变量?

    • Jason Brownlee 2019 年 12 月 16 日下午 1:38 #

      是的,通常这是使用 MSE/RMSE/MAE 等误差度量时的良好方法。

      有选择的启发式方法,但实际上,我测试了一系列转换,并使用最能在此类数据集+模型+超参数中最小化误差的方法。

    • Vinayak 2022 年 8 月 28 日晚上 9:17 #

      如何在生产环境中将预测转换回原始尺度?

  3. Raz 2019 年 12 月 19 日下午 3:22 #

    嗨,Jason,
    非常有用的帖子。我有一个关于我的数据集的问题。在我的数据集中,所有变量(自变量和因变量)的值都在 [-1, 1] 范围内。我还需要将它们归一化到另一个尺度吗?如果不是,这会影响对评估分数的解释吗?
    此致

    • Jason Brownlee 2019 年 12 月 20 日上午 6:39 #

      尝试使用和不使用缩放进行建模,并比较所得模型的性能。

  4. Ali Mohammed Baba 2019 年 12 月 21 日下午 6:08 #

    多好的文章。真的很有帮助。谢谢。

    • Jason Brownlee 2019 年 12 月 22 日上午 6:08 #

      谢谢!

      希望它对您的项目有帮助。

  5. Matthias 2020 年 1 月 22 日上午 2:41 #

    感谢您提供如此出色的教程!也感谢“使用 Keras 深度学习库进行回归教程!”
    我明白了,我可以使用“cross_val_score”了解我的模型的性能。
    但是,如果我想改进我的模型呢?或者只是创建它、拟合它并进行预测?特别是如何将 fitParams 传递给模型?
    您的代码
    pipeline = Pipeline(steps=[(‘normalize’, MinMaxScaler()), (‘model’, HuberRegressor())])
    # 准备带目标缩放的模型
    model = TransformedTargetRegressor(regressor=pipeline, transformer=MinMaxScaler())
    # 这就是我想要做的
    X_train, X_val_and_test, Y_train, Y_val_and_test = train_test_split(X, y, test_size=0.3)
    # 我知道这是错的!
    # history = model.fit(X_train,Y_train,[‘epochs=50’])
    # 这可以工作,但我希望获得更好的结果
    y_resp = model.predict(X_test)

    抱歉,这也许是一个非常基本的问题,但我不知道如何解决。感谢您提供如此出色的教程!也感谢“使用 Keras 深度学习库进行回归教程!”
    我明白了,我可以使用“cross_val_score”了解我的模型的性能。
    但是,如果我想改进我的模型呢?或者只是创建它、拟合它并进行预测?特别是如何将 fitParams 传递给模型?
    您的代码
    pipeline = Pipeline(steps=[(‘normalize’, MinMaxScaler()), (‘model’, HuberRegressor())])
    # 准备带目标缩放的模型
    model = TransformedTargetRegressor(regressor=pipeline, transformer=MinMaxScaler())
    # 这就是我想要做的
    X_train, X_val_and_test, Y_train, Y_val_and_test = train_test_split(X, y, test_size=0.3)
    # 我知道这是错的!
    # history = model.fit(X_train,Y_train,[‘epochs=50’])
    # 这可以工作,但我希望获得更好的结果
    y_resp = model.predict(X_test)

    抱歉,这也许是一个非常基本的问题,但我不知道如何解决。感谢您提供如此出色的教程!也感谢“使用 Keras 深度学习库进行回归教程!”
    我明白了,我可以使用“cross_val_score”了解我的模型的性能。
    但是,如果我想改进我的模型呢?或者只是创建它、拟合它并进行预测?特别是如何将 fitParams 传递给模型?
    您的代码
    pipeline = Pipeline(steps=[(‘normalize’, MinMaxScaler()), (‘model’, HuberRegressor())])
    # 准备带目标缩放的模型
    model = TransformedTargetRegressor(regressor=pipeline, transformer=MinMaxScaler())
    # 这就是我想要做的
    X_train, X_val_and_test, Y_train, Y_val_and_test = train_test_split(X, y, test_size=0.3)
    # 我知道这是错的!
    # history = model.fit(X_train,Y_train,[‘epochs=50’])
    # 这可以工作,但我希望获得更好的结果
    y_resp = model.predict(X_test)

    抱歉,这也许是一个非常基本的问题,但我不知道如何解决。也许我错过了一篇您的帖子。

    此致

    Matthias

  6. Matthias 2020 年 1 月 23 日上午 3:31 #

    非常感谢 Jason,也为我重复插入问题感到抱歉。这里有点混乱。
    我本以为可以通过设置训练 epoch 参数来改进我的结果,这显然对这种类型的模型是错误的。我在此期间已经设法稍微改进了我的结果。

    您是否推荐您的哪本书专门用于回归问题,例如可与波士顿住房数据集问题(各种输入,一两个类似输出)相媲美?

    此致
    Matthias

  7. Matthias 2020 年 1 月 24 日上午 2:05 #

    谢谢 Jason 的帮助。一如既往,一切都解释得非常好。

    此致
    Matthias

  8. Chamsedine AIDARA 2020 年 3 月 6 日晚上 9:36 #

    你好 Jason,谢谢。我实际上正在做一个客户生命价值(回归)项目。
    我的数据集不是线性的。我需要怎么做才能解决这个问题?

    • Jason Brownlee 2020 年 3 月 7 日上午 7:16 #

      我建议测试一系列不同的回归算法,并找出最适合的算法。

  9. Faisal Alsrheed 2020 年 6 月 1 日上午 5:26 #

    你好,Jason 再次 🙂

    我正在使用前馈神经网络进行回归项目。

    在有明确边界的情况下,推荐将 Minmaxscaler 用于目标(Y)而不是 StandardScaler 吗?例如,范围是 100 到 8000?

    我现在只是这样做(Y= Y/8000),并且得到了不错的结果。

    再次感谢您通过您的答案、有用的博客和书籍帮助我们。

  10. Marina 2020 年 6 月 4 日上午 8:49 #

    你好 Jason,谢谢你的教程!有人说不应该缩放目标变量,也没有说明具体情况(你建议这对于回归问题尤其重要)。
    此致,
    Marina

  11. Firas Obeid 2020 年 7 月 9 日上午 5:40 #

    对于 keras/tensorflow 类模型,它是手动完成的,而 TransformedTargetRegressor 不能使用吗?

  12. Sam 2020 年 7 月 16 日下午 1:01 #

    嗨,Jason,

    我偶然发现了这篇文章,只想听听您的想法。

    R 平方真的在实践中毫无用处吗?

    https://data.library.virginia.edu/is-r-squared-useless/

    此致,

    Sam。

    • Jason Brownlee 2020 年 7 月 16 日下午 1:52 #

      我对 r^2 没有强烈意见,也许可以就您的疑虑直接联系作者。

  13. Kingsley Udeh 2020 年 7 月 30 日上午 7:04 #

    嗨,Jason,

    谢谢您的教程。

    我们可以将相同的 TransformedTargetRegressor 实例用于 LSTM 序列模型吗?如果可以,我们该如何修改当前代码?

    • Jason Brownlee 2020 年 7 月 30 日下午 1:43 #

      不,我认为不能。我认为您必须手动准备数据。

  14. Kingsley Udeh 2020 年 7 月 30 日晚上 8:52 #

    谢谢!

  15. Ayoub 2020年8月12日晚上11:06 #

    我们能否使用一个自定义转换器类,在管道中转换目标变量?

  16. Sebastian 2020年8月14日晚上10:35 #

    亲爱的 Jason,

    首先,非常感谢您这篇有趣的教程,它让我买了您的书;请继续保持好的工作!

    我正在尝试为具有 TensorFlow 后端的12个输入、两个输出的 Keras 回归模型实现 GridsearchCV 程序

    def model_opt(n_hidden=1, n_units=32, input_shape=[12])
    model = keras.models.Sequential()

    # 输入层
    model.add(InputLayer(input_shape=input_shape))
    model.add(Dropout(.2))
    # NN_model.add(BatchNormalization())

    # 隐藏层
    for layer in range(n_hidden)
    model.add(Dense(n_units, kernel_initializer=’normal’,activation=’relu’))
    model.add(Dropout(.5))
    # NN_model.add(BatchNormalization())

    # 输出层
    model.add(Dense(2, kernel_initializer=’normal’,activation=’linear’))

    # 编译网络
    model.compile(loss=’mse’, optimizer=’adam’, metrics=[‘mse’])

    return(model)

    我正在尝试将模型嵌入管道,并进行目标转换,正如您上面所示;

    estimators = []
    estimators.append(( ‘scaler’, sklearn.preprocessing.StandardScaler() ))
    estimators.append(( ‘mlp’, keras.wrappers.scikit_learn.KerasRegressor(model_opt) ))
    pipeline = Pipeline(estimators)

    pipe_y = sklearn.compose.TransformedTargetRegressor(regressor=pipeline,
    transformer=sklearn.preprocessing.StandardScaler() )

    hyper_param = {‘mlp__n_hidden’: [1,2,3,4],
    ‘mlp__n_units’: np.power(2, np.arange(5,10))
    }

    rsCV = RandomizedSearchCV(pipe_y, hyper_param, n_iter=10, cv=5, refit=True, random_state=1234)
    rsCV.fit(Xtrain2, ytrain2, mlp__epochs=200, mlp__batch_size=8, mlp__callbacks=callbacks_list);

    但它只是给了我错误

    ValueError: Invalid parameter mlp for estimator TransformedTargetRegressor(regressor=Pipeline(steps=[(‘scaler’,
    StandardScaler()),
    (‘mlp’,
    )]),
    transformer=StandardScaler()). Check the list of available parameters with estimator.get_params().keys().

    您对如何实现这一目标有什么想法吗?

    非常感谢!

    祝好,
    Sebastian

    • Sebastian 2020年8月15日凌晨12:15 #

      嗨,再次,

      我通过将‘hyper_param’对象更改为

      hyper_param = {‘regressor__mlp__n_hidden’: (1,2,3,4),
      ‘regressor__mlp__n_units’: (32, 64, 128, 256, 512)
      }

      来修复它… 这似乎是一个 sklearn 的 bug…

    • Jason Brownlee 2020年8月15日早上6:26 #

      谢谢 Sebastian!

      笼统地说,混合 keras + 多输出 + 网格搜索听起来很有挑战性,直接通过 Keras API 手动运行任何网格搜索会更容易。

      抱歉,我没有明显的解决办法——我没有尝试用管道调整 keras 模型超参数。再说一次,我的直觉是手动运行搜索。

  17. Vinayak Shanawad 2020年8月28日晚上9:36 #

    非常感谢您这篇精彩的文章。

  18. Ale 2020年9月10日凌晨1:45 #

    Jason,有没有办法在管道中包含 inverseTransform,以便 MSE 处于线性比例?

    • Jason Brownlee 2020年9月10日早上6:33 #

      在您进行预测时,它会自动为您进行反向转换。

  19. Owen Lamont 2020年9月30日下午4:34 #

    Jason,文章写得很好,

    我只是想双重检查一下您提到的那一行:

    “然后在调用 fit() 时,将该反向转换应用于提供的任何新数据,以正确的比例返回预测值”

    您是指 predict(),而不是 fit(),对吗?

  20. Rasik Kane 2020年10月26日晚上6:59 #

    嗨,Jason,
    不错的教程。有没有办法使用转换后的列作为分类器?

    • Jason Brownlee 2020年10月27日早上6:42 #

      抱歉,我不明白您的问题。您能重新表述或详细说明一下吗?

  21. Salina 2021年2月16日早上7:53 #

    嗨,Jason,
    是否可以将 TransformedTargetRegressor() 与分类模型一起使用?
    如果不行,是否有任何方法可以使用 sklearn 管道转换分类问题中的多个目标变量?

    • Jason Brownlee 2021年2月16日早上8:02 #

      不,它是用于回归的。

      您可以直接在目标变量上使用标签编码器。

  22. Nush 2021年4月9日早上10:16 #

    如何使用指数和 log(y+1) 这样的目标转换器?它们是否在 PowerTransformer 中可用?

  23. Matt 2021年9月12日凌晨1:24 #

    嗨,Jason,

    非常感谢您的文章。我想根据分位数对数值目标变量进行分类,然后使用分类器。在 sklearn 中,您有 pipline,可以使用此管道进行交叉验证,避免任何数据泄露。我可以使用 TransformedTargetRegressor 来实现此目的吗?——但问题似乎是它总是会转换然后转换回来,对吗?sklearn 中是否有其他方法允许我这样做?

    提前感谢!

    • Adrian Tam
      Adrian Tam 2021年9月14日下午1:16 #

      是的,但如果您已经训练了模型并仅将其用于预测,那不应该是一个问题。

  24. s ranjan 2021年12月1日凌晨1:38 #

    我们在这里是否分别转换了训练和测试的目标变量?如果不是,为什么?

    • Adrian Tam
      Adrian Tam 2021年12月2日凌晨2:04 #

      是的。单独进行,但转换器仅使用训练数据进行拟合。

  25. ML rookie 2022年2月10日凌晨2:50 #

    感谢您的文章。我的问题是何时重新缩放到原始尺度。在网格搜索中进行超参数调整时,应该使用转换后的 y 还是未转换的 y?CV 分数是否应该基于转换后的 y?
    谢谢!

    • James Carmichael 2022年2月12日下午12:56 #

      您好 ML...您应该对数据进行归一化并用于训练。然后将预测值还原到原始尺度并确定分数。

  26. Ueberti 2022年12月1日下午2:00 #

    您知道如何从训练好的神经网络中提取非线性函数吗?我需要提取函数来用于 PSO 优化器。

    训练好的网络

    regressor = Sequential()
    regressor.add(Dense(units = 7, activation = ‘relu’, input_dim = 5))
    #regressor.add(Dense(units = 4, activation = ‘relu’))
    regressor.add(Dense(units = 1, activation = ‘linear’))
    otimizador = keras.optimizers.Adam(lr = 0.001, decay = 0.0001, clipvalue = 0.3)
    regressor.compile(optimizer = otimizador, loss = ‘mean_absolute_error’,
    metrics = [‘mean_absolute_error’])
    regressor.fit(X_train, y_train, epochs = 120)
    prev = regressor.predict(X_test)

    • James Carmichael 2022年12月2日早上7:45 #

      Ueberti,这是一个很好的问题!使用神经网络的好处和原因在于底层的函数映射无法以闭式解获得。如果您有这样的函数,神经网络就不会提供太多价值。

  27. yogini 2023年6月19日晚上10:01 #

    如何对光谱 NIR 数据使用功率变换,其中目标是连续变量,自变量是多变量波长?

留下回复

Machine Learning Mastery 是 Guiding Tech Media 的一部分,Guiding Tech Media 是一家领先的数字媒体出版商,专注于帮助人们了解技术。访问我们的公司网站以了解更多关于我们的使命和团队的信息。