scikit-learn 回归预测结果太好了。我搞砸了啥?

Posted

技术标签:

【中文标题】scikit-learn 回归预测结果太好了。我搞砸了啥?【英文标题】:scikit-learn regression prediction results are too good. What did I mess up?scikit-learn 回归预测结果太好了。我搞砸了什么? 【发布时间】:2019-01-08 08:49:02 【问题描述】:

我们在 Azure ML Studio 平台(最初的拖放系统)之上的 Azure 中运行了一些 ML 模型。一年多来一切都很好,但我们需要继续前进,这样我们才能更好地扩展。因此,我正在使用 scikit-learn 在 Python 中重写这些内容,并在 Jupyter 笔记本中对其进行测试。

好消息/坏消息是我们要训练的数据相当小(数据库中有数百条记录)。这是非常不完美的数据,做出了非常不完美的回归预测,所以错误是可以预料的。这很好。对于这个问题,很好。因为问题是,当我测试这些模型时,预测太完美了。我不明白我做错了什么,但我显然做错了某事

(在我看来)显而易见的事情是我正在对测试数据进行训练,或者通过相关性发现了明显/完美的因果关系。我对train_test_split 的使用告诉我,我没有在我的测试数据上进行训练,我保证第二个是错误的,因为这个空间非常混乱(我们大约 15 年前开始对这些数据进行手动线性回归,并且仍然保持Excel 电子表格能够在紧要关头手动完成,即使它的准确度远低于我们的 Azure ML Studio 模型)。

让我们看一下代码。这是我的 Jupyter 笔记本的相关部分(抱歉,如果有更好的格式化方法):

X = myData
y = myData.ValueToPredict
X_train, X_test, y_train, y_test = train_test_split(
    X, 
    y, 
    train_size = 0.75,
    test_size = 0.25)
print("X_train: ", X_train.shape)
print("y_train: ", y_train.shape)
print("X_test:  ", X_test.shape)
print("y_test:  ", y_test.shape)

X_train: (300, 17)

y_train: (300,)

X_test: (101, 17)

y_test: (101,)

ESTIMATORS = 
    "Extra Trees": ExtraTreesRegressor(criterion = "mse",
                                       n_estimators=10,
                                       max_features=16,
                                       random_state=42),
    "Decision Tree": DecisionTreeRegressor(criterion = "mse",
                                  splitter = "best",
                                       random_state=42),
    "Random Forest": RandomForestRegressor(criterion = "mse",
                                       random_state=42),
    "Linear regression": LinearRegression(),
    "Ridge": RidgeCV(),


y_test_predict = dict()
y_test_rmse = dict()
for name, estimator in ESTIMATORS.items():
    estimator.fit(X_train, y_train)
    y_test_predict[name] = estimator.predict(X_test)
    y_test_rmse[name] = np.sqrt(np.mean((y_test - y_test_predict[name]) ** 2)) # I think this might be wrong but isn't the source of my problem
for name, error in y_test_rmse.items():
    print(name + " RMSE: " + str(error))

额外树 RMSE:0.3843540838630157

决策树 RMSE:0.32838969545222946

随机森林 RMSE:0.4304701784728594

线性回归 RMSE:7.971345895791494e-15

岭 RMSE:0.0001390197344951183

y_test_score = dict()
for name, estimator in ESTIMATORS.items():
    estimator.fit(X_train, y_train)
    y_test_predict[name] = estimator.predict(X_test)
    y_test_score[name] = estimator.score(X_test, y_test)
for name, error in y_test_score.items():
    print(name + " Score: " + str(error))

额外树分数:0.9990166492769291

决策树分数:0.999282165241745

随机森林得分:0.998766521504593

线性回归分数:1.0

岭分数:0.9999999998713534

我想我可能做错了错误指标,所以我只查看了简单的分数(这就是我将两者都包括在内的原因)。然而,两者都表明这些预测好得令人难以置信。请记住,输入量很小(总共约 400 项?)。运行的数据本质上是根据天气模式对商品消费进行预测,这从一开始就是一个混乱的空间,因此应该存在很多错误。

我在这里做错了什么?

(另外,如果我能以更好的方式提出这个问题或提供更多有用的信息,我将不胜感激!)


这是数据的热图。我指出了我们预测的值。

我还绘制了一些更重要的输入与我们预测的值(按另一个维度进行颜色编码):

这是第 2 列,正如 cmets 中所询问的那样


解决方案!

正如@jwil 所指出的,我没有将ValueToPredict 列从X 变量中拉出。解决方案是添加一行以删除该列:

X = myData
y = myData.ValueToPredict
X = X.drop("ValueToPredict", 1) # <--- ONE-LINE FIX!
X_train, X_test, y_train, y_test = train_test_split(
    X, 
    y, 
    train_size = 0.75,
    test_size = 0.25)

有了这个,我的错误和分数会比我预期的要多:

额外树 RMSE:1.6170428819849574

决策树 RMSE:1.990459810552763

随机森林 RMSE:1.699801032532343

线性回归 RMSE:2.5265108241534397

岭 RMSE:2.528721533965162

额外树分数:0.9825944193611161

决策树分数:0.9736274412836977

随机森林得分:0.9807672396970707

线性回归分数:0.9575098985510281

岭分数:0.9574355079097321

【问题讨论】:

您能提供您实际使用的数据吗?您的回归/树中的系数或特征重要性(分别)是什么? 看起来是由于一些过度拟合。请分享数据集。 我不知道如何回答@user3014097 的问题。至于数据,我不能分享它,因为它是非公开数据。如果这是一个过度拟合的问题,我怎样才能让它不太容易做到这一点?我一直在自学这一点——Python 和 ML,总的来说,对我来说还是很新的。我会看看是否可以附上数据的 sns.heatmap - 我认为这可能有助于在一定程度上满足您的要求。 对于线性/岭回归,请查看“estimator.coeff_”,对于树,请查看“estimator.feature_importances_”。我的猜测是一个会比其他的要高得多(在上面的图中显示基本上相关性为 1 的那个) 您正在初始化 X = myDatay = my.ValueToPredict。这对我来说看起来很奇怪。你的意思是写 X = my.Data 还是 y = myData.ValueToPredict 【参考方案1】:

你是对的;我强烈怀疑您的 X 数据中有一个或多个与 Y 数据几乎完全相关的特征。通常这很糟糕,因为这些变量不能解释 Y,而是由 Y 解释或与 Y 共同确定。要解决此问题,请考虑对 X 执行 Y 的线性回归,然后使用简单的 p 值或 AIC/BIC 来确定哪些 X 变量是最不相关的。放下这些并重复这个过程,直到你的 R^2 开始严重下降(尽管每次都会下降一点)。其余变量将与预测最相关,希望您能够从该子集中确定哪些变量与 Y 密切相关。

【讨论】:

那么你是说我对框架的使用,将训练数据与测试数据分开,所有这些都是正确的吗?如果您可以肯定地确认这里的内容是正确的,那么这就是我正在寻找的答案。 等待。在您的代码中,您似乎没有从 X 中删除 ValueToPredict。将该数据分配给 Y 后,您需要确保将其从 X 中删除。这肯定会解决您的问题。 就是这样!!这样做使我的分数下降到 ~95-97% 的水平,这正是我所期望的(99.99999-100% 令人难以置信)。我认为那是正是我的问题。所以我认为train_test_split 知道不在y 列上训练(由y 定义)。我不知道我必须从X 中删除它。 我很高兴这有效! train_test_split 所做的只是将您的观察结果随机分成两组,但两组的所有特征都保持不变。 这绝对是我的错误假设所在。我现在要回顾一些其他的概念验证,在那里我遇到了同样的问题,这解决了很多令人头疼的问题!非常感谢!我大约一个月前第一次打这个,纺了一天,然后把它放在桌子上。从那以后尝试了几次以找出问题所在,但没有成功。希望我能给你买杯啤酒什么的。你为我节省了很多时间!谢谢你,随机聪明的互联网人!

以上是关于scikit-learn 回归预测结果太好了。我搞砸了啥?的主要内容,如果未能解决你的问题,请参考以下文章

我如何识别数据集上的可变目标以进行机器学习预测

scikit-learn 逻辑回归预测与自我实现不同

Scikit-Learn SVR 预测总是给出相同的值

如何在 Python scikit-learn 中输出随机森林中每棵树的回归预测?

使用 scikit-learn 训练线性回归模型后,如何对原始数据集中不存在的新数据点进行预测?

如何在 Python scikit-learn 中输出随机森林中每棵树的回归预测?