为什么scikit-learn的RandomForestRegressor对多个目标的预测有时会总和为1?

在监督学习方法中,我们有特征(输入)和目标(输出)。如果我们有多个维度的目标,它们按行总和为1(例如[0.3, 0.4, 0.3]),为什么当训练数据的总和为1时,scikit-learn的RandomForestRegressor似乎会将所有输出/预测归一化,使其总和为1?

看起来在scikit-learn的源代码中的某个地方,如果训练数据总和为1,它会对输出进行归一化处理,但我没能找到这个部分。我已经查看了BaseDecisionTree,这个类似乎被随机森林使用,但没有看到任何归一化的迹象。我创建了一个gist来展示它的工作原理。当目标的行总和不为1时,回归器的输出也不会总和为1。但当目标的行总和确实为1时,它似乎会进行归一化处理。以下是来自gist的示范代码:

import numpy as npfrom sklearn.ensemble import RandomForestRegressor# 模拟数据# 12行训练数据,6行测试数据,5个特征,3列目标features = np.random.random((12, 5))targets = np.random.random((12, 3))test_features = np.random.random((6, 5))rfr = RandomForestRegressor(random_state=42)rfr.fit(features, targets)preds = rfr.predict(features)print('preds sum to 1?')print(np.allclose(preds.sum(axis=1), np.ones(12)))# 将目标归一化为总和为1norm_targets = targets / targets.sum(axis=1, keepdims=1)rfr.fit(features, norm_targets)preds = rfr.predict(features)te_preds = rfr.predict(test_features)print('predictions all sum to 1?')print(np.allclose(preds.sum(axis=1), np.ones(12)))print('test predictions all sum to 1?')print(np.allclose(te_preds.sum(axis=1), np.ones(6)))

最后一点要注意的是,我尝试在其他随机森林实现中运行类似的拟合(Python中的H2O,R中的rpart, Rborist, RandomForest),但没有找到另一个支持多输出的实现。

我的猜测是scikit-learn的代码中存在一个错误,它在某种程度上混淆了分类和回归,导致输出像分类问题一样被归一化为1。


回答:

这里可能误导人的地方在于,你只关注了输出值的sum结果。当模型使用归一化标签进行训练时,所有预测总和为1的原因是,它只会在它所见过的这些多输出数组中进行预测。这是因为在样本数量较少的情况下,模型会过拟合,决策树实际上像分类器一样工作。

换句话说,来看一个输出未归一化的例子(这同样适用于DecisionTree):

from sklearn.tree import DecisionTreeRegressorfeatures = np.random.random((6, 5))targets = np.random.random((6, 3))rfr = DecisionTreeRegressor(random_state=42)rfr.fit(features, targets)

如果我们现在在一个新的随机特征集上进行预测,我们将得到模型训练过的输出集中的预测值:

features2 = np.random.random((6, 5))preds = rfr.predict(features2)print(preds)array([[0.0017143 , 0.05348525, 0.60877828],  #0       [0.05232433, 0.37249988, 0.27844562],  #1       [0.08177551, 0.39454957, 0.28182183],       [0.05232433, 0.37249988, 0.27844562],       [0.08177551, 0.39454957, 0.28182183],       [0.80068346, 0.577799  , 0.66706668]])print(targets)array([[0.80068346, 0.577799  , 0.66706668],       [0.0017143 , 0.05348525, 0.60877828],  #0       [0.08177551, 0.39454957, 0.28182183],       [0.75093787, 0.29467892, 0.11253746],       [0.87035059, 0.32162589, 0.57288903],       [0.05232433, 0.37249988, 0.27844562]]) #1

所以,逻辑上,如果所有训练输出的总和为1,预测值的总和也会如此。

如果我们取目标和预测值沿第一个轴的sum的交集,我们会看到所有预测值的总和存在于targets中:

preds_sum = np.unique(preds.sum(1))targets_sum = np.unique(targets.sum(1))len(np.intersect1d(targets_sum, preds_sum)) == len(features)# True

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注