将额外参数传递给sklearn管道中的自定义评分函数

时间:2017-10-06 13:27:13

标签: python scikit-learn pipeline

我需要在sklearn中使用自定义分数执行单变量特征选择,因此我使用的是GenericUnivariateSelect。但是,如文档中那样,

选择器的

模式:{'百分位','k_best','fpr','fdr','fwe'}

在我的情况下,我需要选择得分高于某个值的功能,所以我已经实现了:

from sklearn.feature_selection.univariate_selection import _clean_nans
from sklearn.feature_selection.univariate_selection import f_classif                        
import numpy as np
import pandas as pd
from  sklearn.feature_selection import GenericUnivariateSelect
from sklearn.metrics import make_scorer 
from sklearn.feature_selection.univariate_selection import _BaseFilter
from sklearn.pipeline import Pipeline 



class SelectMinScore(_BaseFilter):
    # Sklearn documentation: modes for selectors : {‘percentile’,     ‘k_best’, ‘fpr’, ‘fdr’, ‘fwe’}
    # custom selector: 
    # select features according to the k highest scores.
    def __init__(self, score_func=f_classif, minScore=0.7):
        super(SelectMinScore, self).__init__(score_func)
        self.minScore = minScore
        self.score_func=score_func
    [...]
    def _get_support_mask(self):
        check_is_fitted(self, 'scores_')

        if self.minScore == 'all':
            return np.ones(self.scores_.shape, dtype=bool)
        else:
            scores = _clean_nans(self.scores_)
            mask = np.zeros(scores.shape, dtype=bool)

            # Custom part
            # only score above the min
            mask=scores>self.minScore
            if not np.any(mask):
                mask[np.argmax(scores)]=True
            return mask

但是,我还需要使用自定义分数函数,该函数必须在此处接收额外的参数(XX): 不幸的是,我无法使用make_scorer

解决
def Custom_Score(X,Y,XX):
      return 1

class myclass():
    def mymethod(self,_XX):

            custom_filter=GenericUnivariateSelect(Custom_Score(XX=_XX),mode='MinScore',param=0.7)   
        custom_filter._selection_modes.update({'MinScore': SelectMinScore})
        MyProcessingPipeline=Pipeline(steps=[('filter_step', custom_filter)])
    # finally
        X=pd.DataFrame(data=np.random.rand(500,3))
        y=pd.DataFrame(data=np.random.rand(500,1))
        MyProcessingPipeline.fit(X,y)
        MyProcessingPipeline.transform(X,y)

_XX=np.random.rand(500,1
C=myclass()
C.mymethod(_XX)

这会引发以下错误:

Traceback (most recent call last):

 File "<ipython-input-37-f493745d7e1b>", line 1, in <module>
runfile('C:/Users/_____/Desktop/pd-sk-integration.py', wdir='C:/Users/_____/Desktop')
File "C:\Users\______\AppData\Local\Continuum\Anaconda2\lib\site-packages\spyder\utils\site\sitecustomize.py", line 866, in runfile
execfile(filename, namespace)
File "C:\Users\\______\\AppData\Local\Continuum\Anaconda2\lib\site-packages\spyder\utils\site\sitecustomize.py", line 87, in execfile
exec(compile(scripttext, filename, 'exec'), glob, loc)=
File "C:/Users/______/Desktop/pd-sk-integration.py", line 65, in <module>
C.mymethod()
File "C:/Users/______/Desktop/pd-sk-integration.py", line 55, in mymethod
         custom_filter=GenericUnivariateSelect(Custom_Score(XX=_XX),mode='MinScore',param=0.7)
TypeError: Custom_Score() takes exactly 3 arguments (1 given)

编辑:

我尝试通过在我的kwarg (XX)函数的fit()中添加额外的SelectMinScore并将其作为适合的参数传递来尝试修复。 正如@TomDLT所建议的那样,

custom_filter = SelectMinScore(minScore=0.7)
pipe = Pipeline(steps=[('filter_step', custom_filter)])
pipe.fit(X,y, filter_step__XX=XX)

然而,如果我这样做

line 291, in set_params
(key, self.__class__.__name__))
ValueError: Invalid parameter XX for estimator   SelectMinScore. Check the list of available parameters with `estimator.get_params().keys()`.

1 个答案:

答案 0 :(得分:4)

正如你在the code中看到的那样,得分函数不是用额外的参数调用的,所以目前scikit中没有简单的方法 - 学习传递样本属性XX

对于您的问题,稍微犹豫不决的方法可能是更改fit中的SelectMinScore函数,添加其他参数XX

def fit(self, X, y, XX):
    """...""" 
    X, y = check_X_y(X, y, ['csr', 'csc'], multi_output=True)

    if not callable(self.score_func):
        raise TypeError("The score function should be a callable, %s (%s) "
                        "was passed."
                        % (self.score_func, type(self.score_func)))

    self._check_params(X, y)
    score_func_ret = self.score_func(X, y, XX)
    if isinstance(score_func_ret, (list, tuple)):
        self.scores_, self.pvalues_ = score_func_ret
        self.pvalues_ = np.asarray(self.pvalues_)
    else:
        self.scores_ = score_func_ret
        self.pvalues_ = None

    self.scores_ = np.asarray(self.scores_)

    return self

然后您可以使用extra fit params调用管道:

custom_filter = SelectMinScore(minScore=0.7)
pipe = Pipeline(steps=[('filter_step', custom_filter)])
pipe.fit(X,y, filter_step__XX=XX)