使用scikit-learn(或任何其他python框架)的不同种类的回归量的集合

Mak*_*ich 17 machine-learning scikit-learn ensemble-learning

我正在尝试解决回归任务.我发现有3个模型可以很好地处理不同的数据子集:LassoLARS,SVR和Gradient Tree Boosting.我注意到,当我使用所有这3个模型进行预测然后制作一个"真实输出"表和我的3个模型的输出时,我看到每次至少有一个模型真的接近真实输出,但是其他2个模型可能相对较远.

当我计算最小可能的错误时(如果我从每个测试示例的'最佳'预测器中获取预测),我得到的错误远小于任何模型的错误.所以我想到尝试将这3种不同模型的预测结合到某种集合中.问题是,如何正确地做到这一点?我的所有3个模型都是使用scikit-learn构建和调整的,它是否提供某种方法可用于将模型打包到整体中?这里的问题是我不想仅仅平均来自所有三个模型的预测,我想用加权来做这个,其中加权应该基于特定示例的属性来确定.

即使scikit-learn没有提供这样的功能,如果有人知道如何通过属性来解决这个任务,那就更好了 - 找出数据中每个例子的每个模型的权重.我认为它可以通过在所有这3个模型之上构建的单独的回归器来完成,它将尝试为3个模型中的每个模型输出最佳权重,但我不确定这是否是这样做的最佳方式.

Ami*_*ory 19

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

假设您有两个预测变量,一个基本上是另一个的过度拟合版本,那么前者将出现在火车上比后者更好.由于无法将过度拟合与真正的高质量预测区分开来,因此组合预测器将有利于前者没有真正的原因.

处理这种情况的已知方式是,对于每个预测器,为列中的每一行准备基于适合该行的模型的行的预测.对于过度拟合版本,例如,平均而言,这不会对行产生好的结果.然后,组合预测器将能够更好地评估用于组合较低级别预测器的公平模型.

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)
Run Code Online (Sandbox Code Playgroud)

以下是@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)) 
Run Code Online (Sandbox Code Playgroud)

需要注意的是x0x1是刚吵版本y.我们将前80行用于训练,最后20行用于测试.

这是两个预测​​因子:高方差梯度助推器和线性预测器:

    g = ensemble.GradientBoostingRegressor()
    l = linear_model.LinearRegression()
Run Code Online (Sandbox Code Playgroud)

以下是答案中建议的方法:

    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
Run Code Online (Sandbox Code Playgroud)

现在,使用堆叠:

    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
Run Code Online (Sandbox Code Playgroud)

堆叠预测做得更好.它意识到梯度助推器并不是那么好.

  • 谢谢@MaximHaytovich这就是它需要一个可选的cv函数的原因.如果构建80个预测变量太昂贵(相当于留一个),那么你可能构建8(相当于kfold).不幸的是,正确地进行堆叠本质上更昂贵. (2认同)

Mak*_*ich 10

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

我训练了一组回归模型(如SVR,LassoLars和GradientBoostingRegressor所述).然后我将所有这些数据运行在训练数据上(用于训练这3个回归量中的每一个的相同数据).我得到了每个算法的例子的预测,并将这3个结果保存到pandas数据帧中,列有'predictSVR','predictLASSO'和'predictGBR'.我将最后一列添加到此datafrane中,我将其称为"预测",这是一个真实的预测值.

然后我只是训练这个新数据帧的线性回归:

#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'])
Run Code Online (Sandbox Code Playgroud)

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

stacker.predict() 
Run Code Online (Sandbox Code Playgroud)

关于我的3个回归量的输出.得到一个结果.

这里的问题是我平均找到了回归量的最佳权重,对于我将尝试进行预测的每个例子,权重都是相同的.


And*_*ler 5

你所描述的被称为"堆叠",但尚未在scikit-learn中实现,但我认为贡献是值得欢迎的.平均即将到来的合奏:https://github.com/scikit-learn/scikit-learn/pull/4161

  • 最终裁决是什么?那是堆纸机吗?那一个呢-http://rasbt.github.io/mlxtend/user_guide/regressor/StackingRegressor/? (2认同)

小智 5

迟到的回应,但我想为这种叠加回归方法添加一个实用点(我在工作中经常使用它).

您可能希望为堆栈器选择允许positive = True的算法(例如,ElasticNet).我发现,当你有一个相对较强的模型时,无约束的LinearRegression()模型通常会将较大的正系数拟合到较弱的模型,而负系数则较弱.

除非您确实认为您的较弱模型具有负面预测能力,否则这不是一个有用的结果.非常类似于在常规回归模型的特征之间具有高多重共线性.导致各种边缘效应.

此注释最适用于嘈杂的数据情况.如果你的目标是获得0.9-0.95-0.99的RSQ,你可能想要抛弃那个负面加权的模型.