使用 scikit-learn(或任何其他 python 框架)的不同类型回归器的集合
Ensemble of different kinds of regressors using scikit-learn (or any other python framework)
我正在尝试解决回归任务。我发现有 3 个模型可以很好地处理不同的数据子集:LassoLARS、SVR 和 Gradient Tree Boosting。我注意到,当我使用所有这 3 个模型进行预测,然后对 'true output' 进行 table 和我的 3 个模型的输出时,我发现每次至少有一个模型非常接近真实输出,尽管另外 2 个可能相对较远。
当我计算最小可能误差时(如果我从每个测试示例的 'best' 预测器中进行预测),我得到的误差比任何模型单独的误差小得多。所以我考虑尝试将这 3 个不同模型的预测组合成某种整体。问题是,如何正确地做到这一点?我所有的 3 个模型都是使用 scikit-learn 构建和调整的,它是否提供了某种可用于将模型打包到集成中的方法?这里的问题是我不想只对所有三个模型的预测进行平均,我想通过加权来做到这一点,其中应该根据具体示例的属性来确定权重。
即使 scikit-learn 不提供这样的功能,如果有人知道如何 属性 解决这个任务 - 为数据中的每个示例计算每个模型的权重,那就太好了。我认为这可能是由建立在所有这 3 个模型之上的单独回归器完成的,它将尝试为 3 个模型中的每一个输出最佳权重,但我不确定这是否是最好的方法。
您所描述的称为 "stacking",它尚未在 scikit-learn 中实现,但我认为欢迎贡献。一个仅取平均值的合奏很快就会出现:https://github.com/scikit-learn/scikit-learn/pull/4161
好的,在谷歌搜索 'stacking' 上花了一些时间后(正如@andreas 之前提到的),我发现即使使用 scikit-learn 我也可以在 python 中进行加权。考虑以下:
我训练了一组我的回归模型(如提到的 SVR、LassoLars 和 GradientBoostingRegressor)。然后我 运行 所有这些都在训练数据上(用于训练这 3 个回归器的相同数据)。我使用我的每个算法对示例进行预测,并将这 3 个结果保存到 pandas 数据框中,列为 'predictedSVR'、'predictedLASSO' 和 'predictedGBR'。我将最后一列添加到我称之为 'predicted' 的 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'])
所以当我想对新示例进行预测时,我只是 运行 我的 3 个回归变量中的每一个,然后我做:
stacker.predict()
关于我的 3 个回归器的输出。并得到一个结果。
这里的问题是我正在为回归变量找到最佳权重,平均而言,权重对于我将尝试进行预测的每个示例都是相同的。
这是一个已知的有趣(而且通常很痛苦!)的分层预测问题。在训练数据上训练多个预测器,然后在它们上训练更高的预测器,再次使用训练数据的问题 - 与偏差方差分解有关。
假设您有两个预测器,一个本质上是另一个的过度拟合版本,那么前者将在整个训练集上表现得比后者更好。组合预测器会无缘无故地偏向前者,只是因为它无法区分过度拟合和真正的高质量预测。
处理这个问题的已知方法是,为训练数据中的每一行,为每个预测变量,基于模型not[=42=准备对该行的预测] 适合这一行。例如,对于过度拟合的版本,平均而言,这不会为该行产生好的结果。然后,组合预测器将能够更好地评估用于组合较低级别预测器的公平模型。
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
堆叠预测效果更好。它意识到梯度增强器并不是那么好。
回复晚了,但我想为这种堆叠回归方法(我在工作中经常使用它)添加一个实用点。
您可能希望为堆垛机选择允许 positive=True 的算法(例如 ElasticNet)。我发现,当您有一个相对较强的模型时,不受约束的 LinearRegression() 模型通常会将较大的正系数拟合到较强的模型,将负系数拟合到较弱的模型。
除非您真的相信您的较弱模型具有负面预测能力,否则这不是一个有用的结果。与正则回归模型的特征之间具有高度多重共线性非常相似。导致各种边缘效应。
此评论最适用于嘈杂的数据情况。如果您的目标是获得 0.9-0.95-0.99 的 RSQ,您可能想要丢弃权重为负的模型。
我正在尝试解决回归任务。我发现有 3 个模型可以很好地处理不同的数据子集:LassoLARS、SVR 和 Gradient Tree Boosting。我注意到,当我使用所有这 3 个模型进行预测,然后对 'true output' 进行 table 和我的 3 个模型的输出时,我发现每次至少有一个模型非常接近真实输出,尽管另外 2 个可能相对较远。
当我计算最小可能误差时(如果我从每个测试示例的 'best' 预测器中进行预测),我得到的误差比任何模型单独的误差小得多。所以我考虑尝试将这 3 个不同模型的预测组合成某种整体。问题是,如何正确地做到这一点?我所有的 3 个模型都是使用 scikit-learn 构建和调整的,它是否提供了某种可用于将模型打包到集成中的方法?这里的问题是我不想只对所有三个模型的预测进行平均,我想通过加权来做到这一点,其中应该根据具体示例的属性来确定权重。
即使 scikit-learn 不提供这样的功能,如果有人知道如何 属性 解决这个任务 - 为数据中的每个示例计算每个模型的权重,那就太好了。我认为这可能是由建立在所有这 3 个模型之上的单独回归器完成的,它将尝试为 3 个模型中的每一个输出最佳权重,但我不确定这是否是最好的方法。
您所描述的称为 "stacking",它尚未在 scikit-learn 中实现,但我认为欢迎贡献。一个仅取平均值的合奏很快就会出现:https://github.com/scikit-learn/scikit-learn/pull/4161
好的,在谷歌搜索 'stacking' 上花了一些时间后(正如@andreas 之前提到的),我发现即使使用 scikit-learn 我也可以在 python 中进行加权。考虑以下:
我训练了一组我的回归模型(如提到的 SVR、LassoLars 和 GradientBoostingRegressor)。然后我 运行 所有这些都在训练数据上(用于训练这 3 个回归器的相同数据)。我使用我的每个算法对示例进行预测,并将这 3 个结果保存到 pandas 数据框中,列为 'predictedSVR'、'predictedLASSO' 和 'predictedGBR'。我将最后一列添加到我称之为 'predicted' 的 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'])
所以当我想对新示例进行预测时,我只是 运行 我的 3 个回归变量中的每一个,然后我做:
stacker.predict()
关于我的 3 个回归器的输出。并得到一个结果。
这里的问题是我正在为回归变量找到最佳权重,平均而言,权重对于我将尝试进行预测的每个示例都是相同的。
这是一个已知的有趣(而且通常很痛苦!)的分层预测问题。在训练数据上训练多个预测器,然后在它们上训练更高的预测器,再次使用训练数据的问题 - 与偏差方差分解有关。
假设您有两个预测器,一个本质上是另一个的过度拟合版本,那么前者将在整个训练集上表现得比后者更好。组合预测器会无缘无故地偏向前者,只是因为它无法区分过度拟合和真正的高质量预测。
处理这个问题的已知方法是,为训练数据中的每一行,为每个预测变量,基于模型not[=42=准备对该行的预测] 适合这一行。例如,对于过度拟合的版本,平均而言,这不会为该行产生好的结果。然后,组合预测器将能够更好地评估用于组合较低级别预测器的公平模型。
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
堆叠预测效果更好。它意识到梯度增强器并不是那么好。
回复晚了,但我想为这种堆叠回归方法(我在工作中经常使用它)添加一个实用点。
您可能希望为堆垛机选择允许 positive=True 的算法(例如 ElasticNet)。我发现,当您有一个相对较强的模型时,不受约束的 LinearRegression() 模型通常会将较大的正系数拟合到较强的模型,将负系数拟合到较弱的模型。
除非您真的相信您的较弱模型具有负面预测能力,否则这不是一个有用的结果。与正则回归模型的特征之间具有高度多重共线性非常相似。导致各种边缘效应。
此评论最适用于嘈杂的数据情况。如果您的目标是获得 0.9-0.95-0.99 的 RSQ,您可能想要丢弃权重为负的模型。