使用scikit-learn(或任何其他python框架)集成不同类型的回归器


27

我正在尝试解决回归任务。我发现3个模型对于不同的数据子集运行良好:LassoLARS,SVR和Gradient Tree Boosting。我注意到,当我使用所有这三个模型进行预测,然后制作“真实输出”和这3个模型的输出的表格时,我看到每次至少有一个模型确实接近真实输出,尽管另外两个可能相对较远。

当我计算出最小可能的误差时(如果我从每个测试示例的“最佳”预测变量中获取预测结果),我得到的误差要比任何模型的误差都要小得多。因此,我考虑过尝试将这3种不同模型的预测结合到某种整体中。问题是,如何正确执行此操作?我的所有3个模型都是使用scikit-learn构建和调整的,是否提供了某种可用于将模型打包到集合中的方法?这里的问题是,我不想只是对所有三个模型的平均预测,我想通过加权来做到这一点,应该根据特定示例的属性确定加权。

即使scikit-learn不提供此类功能,如果有人知道如何解决该任务-为数据中的每个示例计算每种模型的权重,也将是一件很好的事情。我认为这可以通过在所有这三个模型之上构建一个单独的回归器来完成,该回归器将尝试为这三个模型中的每个模型输出最佳权重,但是我不确定这是否是最佳方法。

Answers:


32

实际上,scikit-learn确实提供了这样的功能,尽管实现起来可能有些棘手。这是建立在三个模型之上的平均回归器的完整工作示例。首先,让我们导入所有必需的软件包:

from sklearn.base import TransformerMixin
from sklearn.datasets import make_regression
from sklearn.pipeline import Pipeline, FeatureUnion
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from sklearn.neighbors import KNeighborsRegressor
from sklearn.preprocessing import StandardScaler, PolynomialFeatures
from sklearn.linear_model import LinearRegression, Ridge

然后,我们需要将三个回归模型转换为变压器。这将允许我们使用以下命令将其谓词合并为一个特征向量FeatureUnion

class RidgeTransformer(Ridge, TransformerMixin):

    def transform(self, X, *_):
        return self.predict(X)


class RandomForestTransformer(RandomForestRegressor, TransformerMixin):

    def transform(self, X, *_):
        return self.predict(X)


class KNeighborsTransformer(KNeighborsRegressor, TransformerMixin):

    def transform(self, X, *_):
        return self.predict(X)

现在,让我们为弗兰肯斯坦模型定义一个构建器函数:

def build_model():
    ridge_transformer = Pipeline(steps=[
        ('scaler', StandardScaler()),
        ('poly_feats', PolynomialFeatures()),
        ('ridge', RidgeTransformer())
    ])

    pred_union = FeatureUnion(
        transformer_list=[
            ('ridge', ridge_transformer),
            ('rand_forest', RandomForestTransformer()),
            ('knn', KNeighborsTransformer())
        ],
        n_jobs=2
    )

    model = Pipeline(steps=[
        ('pred_union', pred_union),
        ('lin_regr', LinearRegression())
    ])

    return model

最后,让我们拟合模型:

print('Build and fit a model...')

model = build_model()

X, y = make_regression(n_features=10, n_targets=2)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

model.fit(X_train, y_train)
score = model.score(X_test, y_test)

print('Done. Score:', score)

输出:

Build and fit a model...
Done. Score: 0.9600413867438636

为什么要以这种方式使事情复杂化?好的,这种方法允许我们使用scikit-learn诸如GridSearchCV或的标准模块来优化模型超参数RandomizedSearchCV。而且,现在可以轻松地从磁盘上保存和加载预训练的模型。


使用这种方法时,是否有一种简单的方法来提取正在使用的算法/每种算法的比例?
大卫·哈根

也许查看所得线性模型(model.named_steps['lin_regr'].coef_)的系数将使您对整体中的每个模型对最终解决方案的贡献有一些了解。
constt

@constt您是否不需要在基本模型中使用cross_val_predict?在当前实现的基础上,您的顶级模型似乎会从基本模型中获得过度乐观的信号。
布莱恩·比恩

1
这只是一个概念验证的例子,我在这里没有讨论模型选择。我认为此类模型应该进行整体优化,即使用交叉验证方法同时优化所有内置模型的超参数。
constt

如果我们将n_targets = 1设置X, y = make_regression(n_features=10, n_targets=1)为尺寸错误。谁能解释该怎么办?
Mohit Yadav

9

好的,花了一些时间在谷歌搜索后,我发现即使使用scikit-learn我也可以在python中进行加权。考虑以下内容:

我训练了一组回归模型(如提到的SVR,LassoLars和GradientBoostingRegressor)。然后,我将它们全部用于训练数据(用于训练这三个回归变量的相同数据)。我使用每种算法都获得了示例的预测,并将这3个结果保存到“ predictedSVR”,“ predictedLASSO”和“ predictedGBR”列的pandas数据框中。然后将最后一列添加到此数据帧中,我称之为“预测的”,这是一个真实的预测值。

然后,我在这个新的数据帧上训练线性回归:

 #df - dataframe with results of 3 regressors and true output

 from sklearn linear_model
 stacker= linear_model.LinearRegression()
 stacker.fit(df[['predictedSVR', 'predictedLASSO', 'predictedGBR']], df['predicted'])

因此,当我想对新示例进行预测时,我只需分别运行我的三个回归器,然后执行:

 stacker.predict() 

在我的3个回归变量的输出上。并得到结果。

这里的问题是,我正在平均寻找回归变量的最佳权重,对于每个要尝试进行预测的示例,权重都相同。

如果有人对使用当前示例的功能进行堆叠(加权)有任何想法,那么请听听他们的看法。


哇,我非常喜欢这种方法!但是,为什么使用LinearRegression()而不是 LogisticRegression()模型呢?
harrison4

1
@ harrison4因为我在做回归,而不是分类任务?所以我想“加权”每个模型的输出。无论如何,这是一个不好的方法,这里描述了一个好的方法:stackoverflow.com/a/35170149/3633250
Maksim Khaitovich

是的,对不起,您是对的!感谢您分享链接!
harrison17年

5

如果您的数据具有明显的子集,则可以运行像k-means这样的聚类算法,然后将每个分类器与其效果良好的聚类相关联。当一个新的数据点到达时,然后确定它在哪个集群中并运行关联的分类器。

您还可以使用距质心的反距离来获取每个分类器的一组权重,并使用所有分类器的线性组合进行预测。


我发现有一篇论文对这种策略进行了测试(以及对一些类似想法的比较):论文
anthonybell 2015年

有趣的想法,但是要应用它需要大量的工作。谢谢你的论文!
Maksim Khaitovich 2015年

1

一旦所有模型都经过充分训练并表现良好,我将通过以下操作完成一种加权:

  1. 在大量看不见的测试数据上运行所有模型
  2. 将f1分数存储在每个模型每个模型的测试集中
  3. 当您使用合奏进行预测时,每个模型都将为您提供最可能的类别,因此请使用该类别在该模型上的f1分数来加权置信度或概率。如果要处理距离(例如,在SVM中),则只需对距离进行归一化即可获得一般的置信度,然后继续按类f1加权。

您可以通过测量一段时间内正确率的百分比来进一步调整整体。一旦您对新的数据集进行了计分,就可以将阈值以0.1的步长绘制,例如,如果使用该阈值进行计分,则可以针对正确百分数绘制阈值,以了解什么阈值可以给您带来95%的正确率对于第1类,依此类推。您可以在输入新数据时不断更新测试集和f1分数,并跟踪漂移,并在阈值或准确性下降时重建模型。


1
这很有趣,但据我所知,它仅适用于分类任务,而我正在尝试解决回归任务。因此,我无法计算F1分数。
Maksim Khaitovich 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.