繁体   English   中英

scikit-learn分类软标签

[英]scikit-learn classification on soft labels

根据文档,可以为SGDClassifier指定不同的损失函数。 据我所知,对log losscross-entropy损失 function 理论上可以处理软标签,即以某些概率 [0,1] 给出的标签。

问题是:是否可以开箱即用SGDClassifier with log loss function 来解决软标签的分类问题? 如果不是 - 如何使用 scikit-learn 解决此任务(软标签上的线性分类)?

更新:

target的标记方式和问题的性质硬标签不会给出好的结果。 但这仍然是一个分类问题(不是回归),我不想保留对prediction的概率解释,所以回归也不是开箱即用的。 交叉熵损失 function 可以自然地处理target中的软标签。 似乎scikit-learn中线性分类器的所有损失函数都只能处理硬标签。

所以问题大概是:

例如,如何为SGDClassifier指定我自己的损失 function。 似乎scikit-learn并没有坚持这里的模块化方法,需要在它的源代码中的某个地方进行更改

我最近遇到了这个问题,并提出了一个似乎有效的不错的修复方法。

基本上,使用逆 sigmoid 函数将您的目标转换为对数优势比空间。 然后拟合线性回归。 然后,为了进行推理,从线性回归模型中获取预测的 sigmoid。

因此,假设我们有软目标/标签y ∈ (0, 1) (确保将目标限制为[1e-8, 1 - 1e-8]以避免在我们记录日志时出现不稳定问题)。

我们采用逆 sigmoid,然后我们拟合线性回归(假设预测变量在矩阵X ):

y = np.clip(y, 1e-8, 1 - 1e-8)   # numerical stability
inv_sig_y = np.log(y / (1 - y))  # transform to log-odds-ratio space

from sklearn.linear_model import LinearRegression
lr = LinearRegression()
lr.fit(X, inv_sig_y)

然后进行预测:

def sigmoid(x):
    ex = np.exp(x)
    return ex / (1 + ex)

preds = sigmoid(lr.predict(X_new))

这似乎有效,至少对于我的用例。 我的猜测是,无论如何,LogisticRegression 的幕后发生的事情都不远了。

奖励:这似乎也适用于sklearn其他回归模型,例如RandomForestRegressor

根据文档

“log”损失给出了逻辑回归,一种概率分类器。

通常,损失函数的形式为Loss( prediction, target ) ,其中prediction是模型的输出, target是真实值。 在逻辑回归的情况下, prediction(0,1)上的值(即“软标签”),而target01 (即“硬标签”)。

因此,在回答您的问题时,这取决于您指的是prediction还是target 一般来说,标签的形式(“硬”或“软”)由为prediction选择的算法和target手头数据给出。

如果您的数据具有“硬”标签,并且您希望模型输出“软”标签(可以设置阈值以提供“硬”标签),那么是的,逻辑回归属于这一类。

如果您的数据具有“软”标签,那么在使用典型分类方法(即逻辑回归)之前,您必须选择一个阈值将它们转换为“硬”标签。 否则,您可以使用模型适合的回归方法来预测“软”目标。 在后一种方法中,您的模型可能会给出(0,1)之外的值,并且必须对此进行处理。

对于那些感兴趣的人,我已经实现了一个自定义的 class,它的行为类似于普通分类器,但在构造函数中采用任何回归器来执行@nlml 建议的转换:

from sklearn.base import BaseEstimator, ClassifierMixin
from sklearn.utils.validation import check_array
from scipy.special import softmax
import numpy as np

def _log_odds_ratio_scale(X):
    X = np.clip(X, 1e-8, 1 - 1e-8)   # numerical stability
    X = np.log(X / (1 - X))  # transform to log-odds-ratio space
    return X

class FuzzyTargetClassifier(ClassifierMixin, BaseEstimator):
        
    def __init__(self, regressor):
        '''
        Fits regressor in the log odds ratio space (inverse crossentropy) of target variable.
        during transform, rescales back to probability space with softmax function
        
        Parameters
        ---------
        regressor: Sklearn Regressor
            base regressor to fit log odds ratio space. Any valid sklearn regressor can be used here.
        
        '''
        
        self.regressor = regressor
        return
    
    def fit(self, X, y=None, **kwargs):
        #ensure passed y is onehotencoded-like
        y = check_array(y, accept_sparse=True, dtype = 'numeric', ensure_min_features=1)
        self.regressors_ = [clone(self.regressor) for _ in range(y.shape[1])]
        for i in range(y.shape[1]):
            self._fit_single_regressor(self.regressors_[i], X, y[:,i], **kwargs)
        
        return self
    
    def _fit_single_regressor(self, regressor, X, ysub, **kwargs):
        ysub = _log_odds_ratio_scale(ysub)        
        regressor.fit(X, ysub, **kwargs)
        return regressor    
        
    def decision_function(self,X):
        all_results = []
        for reg in self.regressors_:
            results = reg.predict(X)
            if results.ndim < 2:
                results = results.reshape(-1,1)
            all_results.append(results)
        
        results = np.hstack(all_results)                
        return results
    
    def predict_proba(self, X):
        results = self.decision_function(X)
        results = softmax(results, axis = 1)
        return results
    
    def predict(self, X):
        results = self.decision_function(X)
        results = results.argmax(1)
        return results

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM