【问题标题】:Why do predictions of multiple targets sometimes sum to 1 with sklearn RandomForestRegressor?为什么使用 sklearn RandomForestRegressor 对多个目标的预测有时总和为 1?
【发布时间】:2020-08-20 16:42:24
【问题描述】:

使用监督学习方法,我们有特征(输入)和目标(输出)。如果我们有按行求和为 1 的多维目标(例如 [0.3, 0.4, 0.3]),为什么 sklearn 的 RandomForestRegressor 似乎在训练数据之和为 1 时将所有输出/预测归一化为 1?

似乎在 sklearn 的源代码中的某个地方,如果训练数据的总和为 1,它正在对输出进行规范化,但我无法找到它。我已经到了BaseDecisionTree class,它似乎被随机森林使用,但在那里看不到任何规范化。我创建了一个gist 来展示它是如何工作的。当目标的逐行总和不等于 1 时,回归器的输出总和不等于 1。但是当目标的逐行总和总和为 1 时,它似乎对其进行了归一化。这是来自 gist 的演示代码:

import numpy as np
from sklearn.ensemble import RandomForestRegressor

# simulate data
# 12 rows train, 6 rows test, 5 features, 3 columns for target
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)))


# normalize targets to sum to 1
norm_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)中运行类似的拟合,但没有找到另一个允许多个输出的实现。

我的猜测是 sklearn 代码中存在一个错误,它以某种方式混淆了分类和回归,并且输出被归一化为 1,就像分类问题一样。

【问题讨论】:

    标签: python machine-learning scikit-learn random-forest


    【解决方案1】:

    这里可能会产生误导,因为您只查看输出值的结果sum。使用归一化标签训练模型时所有预测加起来为 1 的原因是,它只会在它看到的 这些 多输出数组中进行预测。发生这种情况是因为样本太少,模型过拟合,决策树实际上就像一个分类器。

    换句话说,查看输出未标准化的示例(同样适用于DecisionTree):

    from sklearn.tree import DecisionTreeRegressor
    
    features = 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,那么预测值也将如此。

    如果我们沿第一轴为目标值和预测值取sums 的交点,我们会看到所有预测值的总和都存在于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
    

    【讨论】:

    • 啊,我认为这是朝着正确的方向发展。它预测目标的确切值这一事实看起来像是极度过拟合,也许这就是样本加起来为 1 时发生的情况。为了测试这一点,我们需要将树的深度限制为 2 或 3,或者使min_samples_leaf 大于 1。
    • 是的 @wordsforthewise 当决策树回归器明显过拟合时,它们往往表现得像分类器,即它们只能在他们看到的值中进行预测。更新以澄清这一点
    猜你喜欢
    • 2018-03-23
    • 2020-07-11
    • 1970-01-01
    • 2020-04-15
    • 2019-12-27
    • 2018-01-04
    • 2018-08-24
    • 2020-11-13
    • 1970-01-01
    相关资源
    最近更新 更多