Python Scikit-learn MultiOutput Regression - 在预测数值时强制执行下限

Posted

技术标签:

【中文标题】Python Scikit-learn MultiOutput Regression - 在预测数值时强制执行下限【英文标题】:Python Scikit-learn MultiOutput Regression - enforce floor limit when predicting numerical values 【发布时间】:2021-03-25 05:29:41 【问题描述】:

我在下面有一个非常简单的程序,它使用多输出回归构建模型。尽管所有训练数据都包含正浮点值,但我发现所做的预测通常会产生负值。我如何告诉 scikit 强制执行 0 的下限(或者换句话说,不要做出负面预测)?

import csv
from sklearn.multioutput import MultiOutputRegressor
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.model_selection import train_test_split

X = []
Y = []

results = []
with open("folder/training_data.csv") as csvfile:
    reader = csv.reader(csvfile, quoting=csv.QUOTE_NONNUMERIC)
    for row in reader:  # each row is a list
        x = row[:5]
        y = row[5:]
        X.append(x)
        Y.append(y)

xtrain, xtest, ytrain, ytest = train_test_split(X, Y, test_size=0.15)

gbr = GradientBoostingRegressor()
model = MultiOutputRegressor(estimator=gbr)

model.fit(xtrain, ytrain)

...


prediction = model.predict([[1.0,2.0,3.0,4.0,5.0]])

# I get e.g. [[-0.2, -0.1]] back where I'd rather have [[0,0]]

【问题讨论】:

【参考方案1】:

问题不在MultiOutputRegressor。而是GradientBoostingRegressor

一般来说,回归量可能会产生一些超出y 值范围的奇怪输出。然而,如果您的 xtestytest 不包含负值,也不远离训练集分布(相当随意,或者换句话说,不是来自相同的训练集分布,这只是在理论上,作为一个可能的原因),除了我们的伙伴GradientBoostingRegressor! 之外,大多数回归变量不太可能出现这些负值。

问题的发生可能是因为GradientBoostingRegressor 的工作方式。如果您阅读它,您会发现:

GB 以前向阶段方式构建加法模型;它允许 用于优化任意可微损失函数。在 每个阶段都有一个回归树适合于 给定损失函数。

这意味着每个阶段都将回归树拟合到前一阶段的残差,现在如果给定样本的误差很大(即损失很大),它将在该阶段产生负值。因此,算法在对所有树的值求和时得出负输出并非不可能。

您可以尝试通过改进模型来解决此问题,例如减少n_estimators,或尝试不同的损失函数..等等。

您可以阅读here 了解完整的参数列表。

最后,您可能还想考虑使用GridSearchCV along with MultiOutputRegressor,这可能会有所帮助。


PS:如果您使用的向量 [1.0,2.0,3.0,4.0,5.0] 与您的训练数据完全不同(即相当随意),那么根据我在上面解释过。事实上,其他回归器可能会输出奇怪的预测来响应他们认为的“奇怪的输入”!。如果后者尤其如此,那么除了用另一个产生负值的函数来包装预测函数 --> 零之外,别无他法,就像这样(如果需要,进行必要的检查和调整):

def predict(model, sample):
    res = model.predict(sample)
    return res[res < 0] = 0

【讨论】:

>> nor are far a way from the training set 你怎么知道的?为什么不考虑将训练区域外推作为主要原因? @SergeyBushmanov 阅读我的更新,我的意思是“相当随意”。由于预计测试集将来自训练集的相同统计分布。这是一个理论上的讨论,并不意味着 OP 应该在实践中确保这一点(尽管有一些措施可以查看两个分布彼此相距多远)。 感谢您对原因的回答和解释【参考方案2】:

如果您的训练目标始终高于 0,您可以尝试使用 tweedie 损失或泊松损失。

https://scikit-learn.org/stable/modules/generated/sklearn.metrics.mean_tweedie_deviance.html

我不知道 GBM 是否支持这 2,但 XGBoost 和 HistBoost 支持:

    https://xgboost.readthedocs.io/en/stable/parameter.html#parameters-for-tweedie-regression-objective-reg-tweedie https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.HistGradientBoostingRegressor.html:

“泊松”损失实际上实现了“半最小二乘损失”和“半泊松偏差”来简化梯度的计算。此外,“泊松”损失在内部使用对数链接并且要求 y >= 0。

BR /埃德加

【讨论】:

以上是关于Python Scikit-learn MultiOutput Regression - 在预测数值时强制执行下限的主要内容,如果未能解决你的问题,请参考以下文章

使用 scikit-learn 进行多标签文本分类,使用哪些分类器?

scikit-learn 在多标签分类中计算 F1

树莓派上的 scikit-learn/python3

Python---scikit-learn(sklearn)模块

Python中计算TF-IDF(scikit-learn)

scikit-learn( Macine Learning in Python )