为sklearn梯度提升分类器设置自定义损失函数

4
Sklearn梯度提升分类器接受偏差和指数损失,详见此处此处。但是,我们能否传递自定义的损失函数而不是预定义的损失函数('deviance'或'exponential'损失)?

stackoverflow上类似的问题及其未回答之处:

我已经找到了这个问题,它看起来最相关。但是,它根本没有回答我的问题,因为它没有讨论如何将自定义损失传递给GradientBoostingClassifier

还有一个相关的问题,但是答案没有解释一旦你定义了一个类(如答案中所述),你如何将其作为参数传递给GradientBoostingClassifier。

2个回答

3
为此,您应该创建 "BaseGradientBoosting" 的子类,以及第一个子类和 GradientBoostingClassifier(在分类情况下)类的子类。在第一个类中,您应该在 super().__init__ 中传递自定义损失函数的名称,在第二个子类中,您可以将自定义损失函数的名称作为 _SUPPORTED_LOSS 传递。
此外,要关闭 SKlearn 梯度提升中 _check_paramsValueError,您必须重写此函数或考虑对此函数进行异常处理。
例如:
class my_base_gradient_boost(BaseGradientBoosting, metaclass=ABCMeta):
    @abstractmethod
    def __init__(self, *args):
       super().__init__(loss='my_custom_loss', *other_args)

    def _check_params(self):
      try:
        super()._check_params()
      except ValueError as e:
        if str(e) == "Loss 'my_costum_loss' not supported. ":
            self.loss_ = self.my_costum_loss
        else:
            raise

class my_classifier(my_base_gradient_boost, GradientBoostingClassifier):

    _SUPPORTED_LOSS = ('my_costum_loss')

    @_deprecate_positional_args           
    def __init__(self, *args):
        super().__init__(*args)

请记住,*args是BaseGradientBoosting的所有参数。
这是很多工作,但我找不到更好的解决方案。希望这有所帮助。
顺便说一下,你是对的,提到的链接并没有回答你的问题。

0
这是一个简单的例子,展示了如何在梯度提升回归器中使用自定义损失函数。我创建了一个自定义损失函数,以便对0进行不同的加权处理,因为我遇到了零膨胀的情况。但你也可以根据自己的需求来定制损失函数。
这种逻辑可以应用于许多sklearn方法中。
class CustomGradientBoostingRegressor(GradientBoostingRegressor):
    def __init__(self, penalty_factor=5, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.penalty_factor = penalty_factor

    def fit(self, X, y, sample_weight=None):
        # Custom logic to compute the loss, giving higher penalty for errors when y_true is zero
        super().fit(X, y, sample_weight=sample_weight)
        loss = np.abs(y - self.predict(X))
        loss[y == 0] *= self.penalty_factor
        return self

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接