【问题标题】:Linear regression: Good results for training data, horrible for test data线性回归:训练数据的结果很好,测试数据的结果很糟糕
【发布时间】:2018-11-20 09:13:50
【问题描述】:

我正在使用大约 400.000 x 250 的数据集。 我对模型在训练集上测试时产生非常好的 R^2 分数有疑问,但在测试集上使用时却非常糟糕。最初,这听起来像是过拟合。但是数据被随机分成训练/测试集,而且数据集很大,所以我觉得必须有别的东西。 有什么建议吗?

将数据集拆分为训练集和测试集

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(df.drop(['SalePrice'], 
axis=1), df.SalePrice, test_size = 0.3)

Sklearn 的线性回归估计器

from sklearn import linear_model
linReg = linear_model.LinearRegression()    # Create linear regression object
linReg.fit(X_train, y_train)                # Train the model using the training sets

# Predict from training set
y_train_linreg = linReg.predict(X_train)

# Predict from test set
y_pred_linreg = linReg.predict(X_test)

指标计算

from sklearn import metrics
metrics.r2_score(y_train, y_train_linreg)
metrics.r2_score(y_test, y_pred_linreg)

在训练集上测试时的 R^2 得分:0,64

在测试集上测试时的 R^2 得分:-10^23(大约)

【问题讨论】:

  • 您是否尝试过交叉验证(使用不同部分的数据进行多次训练和测试)。也许当前训练和测试中的数据分布不允许模型了解测试中的数据(因为训练中不存在类似的数据)。
  • 您是否尝试过应用任何特征转换/预处理方法?例如MinMaxScaler 然后使用交叉验证来评估性能?

标签: python scikit-learn linear-regression


【解决方案1】:

虽然我同意 Mihai 的观点,即您的问题肯定看起来像过拟合,但我不一定同意他的回答,即神经网络可以解决您的问题;至少,不是开箱即用。就其本身而言,神经网络对线性模型的过度拟合更多,而不是更少。您需要以某种方式处理您的数据,几乎没有任何模型可以为您做到这一点。您可能会考虑的几个选项(抱歉,如果不查看数据集,我不能更准确):

  • 最简单的事情,使用正则化。 400k 行很多,但如果有 250 个维度,您几乎可以随意过度拟合。所以尝试用 Ridge 或 Lasso(或 Elastic Net 或其他)替换 LinearRegression。见http://scikit-learn.org/stable/modules/linear_model.html(Lasso 的优势在于为你丢弃特征,见下一点)
  • 特别是如果您想超越线性模型(并且您可能应该这样做),建议首先减少问题的维度,正如我所说的 250 很多。在这里尝试使用一些特征选择技术:http://scikit-learn.org/stable/modules/feature_selection.html
  • 也许最重要的是,您应该考虑调整您的输入数据。我要尝试的第一件事是,假设您真的想预测代码所暗示的价格,用它的对数或 log(1+x) 替换它。否则,线性回归将非常非常努力地拟合以 100 万美元出售的单个对象,而忽略低于 1000 美元的所有内容。同样重要的是,检查您是否有任何非数字(分类)列并仅在需要时保留它们,以防将它们减少为宏观类别:具有 1000 个可能值的分类列将使您的问题维度增加 1000,使这是有保证的过拟合。对于每个输入(例如买家姓名),具有唯一分类数据的单列将直接引导您完美过度拟合。
  • 在这一切之后(清理数据,通过上述任一方法或仅使用 Lasso 回归来降低维度,直到您得到肯定小于 100,可能小于 20 - 请记住,这包括任何分类数据!),您应该考虑使用非线性方法来进一步改善您的结果 - 但这在您的线性模型为您提供至少一些温和的正 R^2 测试数据值之前是没有用的。 sklearn 提供了很多:http://scikit-learn.org/stable/modules/kernel_ridge.html 是开箱即用的最容易使用(也可以进行正则化),但在您的情况下使用它可能太慢(您应该首先尝试这个,以及任何接下来,在您的数据子集上,说 1000 行,一旦您只选择了 10 或 20 个特征,看看这有多慢)。 http://scikit-learn.org/stable/modules/svm.html#regression 有许多不同的口味,但我认为除了线性的之外,其他的都太慢了。坚持线性事物,http://scikit-learn.org/stable/modules/sgd.html#regression 可能是最快的,这也是我在这么多样本上训练线性模型的方式。真正脱离线性,最简单的技术可能包括某种树,直接http://scikit-learn.org/stable/modules/tree.html#regression(但这几乎肯定是过拟合),或者更好的是,使用一些集成技术(随机森林http://scikit-learn.org/stable/modules/ensemble.html#forests-of-randomized-trees是典型的go-对于算法,梯度提升http://scikit-learn.org/stable/modules/ensemble.html#gradient-tree-boosting 有时效果更好)。最后,最先进的结果确实通常是通过神经网络获得的,参见例如http://scikit-learn.org/stable/modules/neural_networks_supervised.html 但是对于这些方法,sklearn 通常不是正确的答案,您应该查看专用环境(TensorFlow、Caffe、PyTorch 等)...但是如果您不熟悉这些方法,那肯定不值得麻烦!

【讨论】:

  • 这是非常清晰和全面的指南。两个附加组件 1) 在第 3 点上,我还将将特征缩放添加到零均值和单位方差(使用 StandardScalerRobustScaler。如果我没记错的话,线性模型会受到比例差异的影响。 2) 最后一点,我会推荐 LightGBM/CatBoost 或 XGBoost 而不是 sklean GBM 实现,因为它们要快得多
  • @MykhailoLisovyi 非常感谢您在我的答案中添加了详细信息,确实忽略了对数据的居中和重新缩放对我来说是一个很大的失误,因为它们非常需要!还要感谢您指出更好的提升实现,因为我只知道 XGBoost,这部分答案对我也很有用:-)
  • 只是为了记录,有几个基准测试飞来飞去,这表明在 CPU 上 LightGBM 和 CatBoost 优于 XGBoost(有一些基准测试表明 XGBoost 在 GPU 上至少比 LightGBM 更快,但我没有在 GPU 上训练他们,所以我不能分享个人经验)。而且这三个都比sklearn的实现要快得多。所以玩这些包是非常有用的。
  • 感谢您的详细回复。我已经完成了特征变量的缩放。然而,切换到 Ridge 确实产生了更好的结果,训练数据和测试数据之间几乎没有区别 :)
猜你喜欢
  • 2019-03-02
  • 1970-01-01
  • 1970-01-01
  • 2016-10-09
  • 1970-01-01
  • 2017-06-22
  • 2016-10-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多