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

Machine learning 使用scikit learn(或任何其他python框架)集成不同类型的回归器,machine-learning,scikit-learn,ensemble-learning,Machine Learning,Scikit Learn,Ensemble Learning,我正在努力解决回归任务。我发现有3个模型可以很好地用于不同的数据子集:Lassolas、SVR和Gradient Tree Boosting。我注意到,当我使用所有这3个模型进行预测,然后制作一个“真实输出”表和我的3个模型的输出时,我发现每次至少有一个模型非常接近真实输出,尽管另外两个可能相对较远 当我计算最小可能误差时(如果我从每个测试示例的“最佳”预测值中进行预测),我得到的误差比任何模型的误差都小得多。所以我想尝试将这3个不同模型的预测组合成某种集合。问题是,如何正确地做到这一点?我的3

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

当我计算最小可能误差时(如果我从每个测试示例的“最佳”预测值中进行预测),我得到的误差比任何模型的误差都小得多。所以我想尝试将这3个不同模型的预测组合成某种集合。问题是,如何正确地做到这一点?我的3个模型都是使用scikit learn构建和调整的,它是否提供了某种方法,可以用于将模型打包到集成中?这里的问题是,我不想仅仅对所有三个模型的预测进行平均,我想通过加权来实现这一点,加权应该根据特定示例的属性来确定


即使scikit learn不提供这样的功能,如果有人知道如何解决这一任务——计算数据中每个示例的每个模型的权重,那就太好了。我认为这可能是由一个建立在所有这3个模型之上的独立回归器来完成的,该回归器将尝试为3个模型中的每一个输出最佳权重,但我不确定这是否是最好的方法。

您所描述的被称为“堆叠”,这在scikit learn中尚未实现,但我认为欢迎您的贡献。一个仅仅是平均值的集合很快就会出现:

好吧,在花了一些时间在谷歌上搜索“堆叠”(正如@andreas之前提到的)之后,我发现即使使用scikit learn,我也可以用python进行加权。考虑下面的内容:

我训练了一组回归模型(如SVR、LassoLars和GradientBoostingRegressionor所述)。然后,我在训练数据上运行所有这些数据(这3个回归中的每一个都使用相同的数据)。我用我的每一种算法对示例进行预测,并将这3个结果保存到带有“predictedSVR”、“predictedLASSO”和“PredictedBr”列的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'])
因此,当我想对新示例进行预测时,我只需分别运行我的3个回归器中的每一个,然后进行:

stacker.predict() 
关于我的3个回归器的输出。并得到一个结果


这里的问题是,我正在为回归者寻找最佳权重。平均而言,我将尝试进行预测的每个示例的权重都是相同的。

这是一个已知的有趣(通常是痛苦的!)分层预测问题。在训练数据上训练多个预测器,然后在训练数据上训练更高的预测器,再次使用训练数据的问题,与偏差-方差分解有关

假设您有两个预测值,一个基本上是另一个的过度拟合版本,那么前者将在列车组上显示为优于后者。组合预测将无真正原因地支持前者,因为它无法区分过度拟合和真正的高质量预测

处理这一问题的已知方法是,基于不适合该行的模型,为列车数据中的每一行,为每一个预测器,准备该行的预测。例如,对于过拟合版本,这平均不会为行生成良好的结果。然后,组合预测因子将能够更好地评估用于组合较低级别预测因子的公平模型

Shahar Azulay&我写了一个变压器阶段来处理这个问题:

class Stacker(object):
    """
    A transformer applying fitting a predictor `pred` to data in a way
        that will allow a higher-up predictor to build a model utilizing both this 
        and other predictors correctly.

    The fit_transform(self, x, y) of this class will create a column matrix, whose 
        each row contains the prediction of `pred` fitted on other rows than this one. 
        This allows a higher-level predictor to correctly fit a model on this, and other
        column matrices obtained from other lower-level predictors.

    The fit(self, x, y) and transform(self, x_) methods, will fit `pred` on all 
        of `x`, and transform the output of `x_` (which is either `x` or not) using the fitted 
        `pred`.

    Arguments:    
        pred: A lower-level predictor to stack.

        cv_fn: Function taking `x`, and returning a cross-validation object. In `fit_transform`
            th train and test indices of the object will be iterated over. For each iteration, `pred` will
            be fitted to the `x` and `y` with rows corresponding to the
            train indices, and the test indices of the output will be obtained
            by predicting on the corresponding indices of `x`.
    """
    def __init__(self, pred, cv_fn=lambda x: sklearn.cross_validation.LeaveOneOut(x.shape[0])):
        self._pred, self._cv_fn  = pred, cv_fn

    def fit_transform(self, x, y):
        x_trans = self._train_transform(x, y)

        self.fit(x, y)

        return x_trans

    def fit(self, x, y):
        """
        Same signature as any sklearn transformer.
        """
        self._pred.fit(x, y)

        return self

    def transform(self, x):
        """
        Same signature as any sklearn transformer.
        """
        return self._test_transform(x)

    def _train_transform(self, x, y):
        x_trans = np.nan * np.ones((x.shape[0], 1))

        all_te = set()
        for tr, te in self._cv_fn(x):
            all_te = all_te | set(te)
            x_trans[te, 0] = self._pred.fit(x[tr, :], y[tr]).predict(x[te, :]) 
        if all_te != set(range(x.shape[0])):
            warnings.warn('Not all indices covered by Stacker', sklearn.exceptions.FitFailedWarning)

        return x_trans

    def _test_transform(self, x):
        return self._pred.predict(x)

以下是@MaximHaytovich回答中描述的设置改进示例

首先,一些设置:

    from sklearn import linear_model
    from sklearn import cross_validation
    from sklearn import ensemble
    from sklearn import metrics

    y = np.random.randn(100)
    x0 = (y + 0.1 * np.random.randn(100)).reshape((100, 1)) 
    x1 = (y + 0.1 * np.random.randn(100)).reshape((100, 1)) 
    x = np.zeros((100, 2)) 
请注意,
x0
x1
只是
y
的嘈杂版本。我们将使用前80行进行训练,最后20行进行测试

这是两个预测器:更高的方差梯度增强器和线性预测器:

    g = ensemble.GradientBoostingRegressor()
    l = linear_model.LinearRegression()
以下是答案中建议的方法:

    g.fit(x0[: 80, :], y[: 80])
    l.fit(x1[: 80, :], y[: 80])

    x[:, 0] = g.predict(x0)
    x[:, 1] = l.predict(x1)

    >>> metrics.r2_score(
        y[80: ],
        linear_model.LinearRegression().fit(x[: 80, :], y[: 80]).predict(x[80: , :]))
    0.940017788444
现在,使用堆叠:

    x[: 80, 0] = Stacker(g).fit_transform(x0[: 80, :], y[: 80])[:, 0]
    x[: 80, 1] = Stacker(l).fit_transform(x1[: 80, :], y[: 80])[:, 0]

    u = linear_model.LinearRegression().fit(x[: 80, :], y[: 80])

    x[80: , 0] = Stacker(g).fit(x0[: 80, :], y[: 80]).transform(x0[80:, :])
    x[80: , 1] = Stacker(l).fit(x1[: 80, :], y[: 80]).transform(x1[80:, :])

    >>> metrics.r2_score(
        y[80: ],
        u.predict(x[80:, :]))
    0.992196564279

叠加预测效果更好。它意识到梯度助推器并没有那么好。

响应较晚,但我想为这种叠加回归方法(我在工作中经常使用这种方法)添加一个实用点

您可能希望为堆垛机选择一种允许正=真的算法(例如,ElasticNet)。我发现,当你有一个相对较强的模型时,无约束线性回归()模型通常会对较强的模型拟合一个较大的正系数,对较弱的模型拟合一个负系数

除非你真的相信你较弱的模型具有负面预测能力,否则这不是一个有益的结果。非常类似于在正则回归模型的特征之间具有高度的多重共线性。导致各种边缘效果


此注释最适用于嘈杂的数据情况。如果你的目标是得到0.9-0.95-0.99的RSQ,你可能会想扔掉得到负权重的模型

谢谢。在谷歌搜索了一段时间有关堆叠的信息后,我发现了如何进行“堆叠”,不仅仅是使用多数票规则(或平均),而是使用一些更先进的方法。我将很快在回答中发布。在统计学习的要素中有一个很好的描述。@AndreasMueller请看下面我的回答。关于你关于欢迎投稿的评论,如果有兴趣的话,我很乐意尝试投稿。我不确定我是否遵循你的代码,但我不认为这是错误的。调用
fit
时,您只能安装一个