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
值范围的奇怪输出。然而,如果您的 xtest
和 ytest
不包含负值,也不远离训练集分布(即相当随意,或者换句话说,不是来自相同的训练集分布,这只是在理论上,作为一个可能的原因),除了我们的伙伴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 进行多标签文本分类,使用哪些分类器?