簡體   English   中英

如何在scikit-learn中對管道中的轉換參數進行網格搜索

[英]How to gridsearch over transform arguments within a pipeline in scikit-learn

我的目標是使用一種模型選擇最重要的變量,使用另一種模型使用這些變量進行預測。 在下面的示例中,我使用了兩個RandomForestClassifiers,但是第二個模型可以是任何其他分類器。

RF具有帶有閾值自變量的變換方法。 我想對不同的可能閾值參數進行網格搜索。

這是一個簡化的代碼片段:

# Transform object and classifier
rf_filter = RandomForestClassifier(n_estimators=200, n_jobs=-1, random_state=42, oob_score=False)
clf = RandomForestClassifier(n_jobs=-1, random_state=42, oob_score=False)

pipe = Pipeline([("RFF", rf_filter), ("RF", clf)])

# Grid search parameters
rf_n_estimators = [10, 20]
rff_transform = ["median", "mean"] # Search the threshold parameters

estimator = GridSearchCV(pipe,
                         cv = 3, 
                         param_grid = dict(RF__n_estimators = rf_n_estimators,
                                           RFF__threshold = rff_transform))

estimator.fit(X_train, y_train)

錯誤為ValueError: Invalid parameter threshold for estimator RandomForestClassifier

我認為這行得通,因為文檔說:

如果為None且可用,則使用對象屬性閾值。

我嘗試在網格搜索之前設置閾值屬性( rf_filter.threshold = "median" ),並且它起作用了; 但是,我不知道如何在其上進行網格搜索。

是否有一種方法可以迭代分類器的transform方法中通常期望提供的不同參數?

按照您所描述的相同方法,即使用兩個不同的“隨機森林”分類器進行分組來對特征進行選擇和分類,然后遇到了相同的問題。

RandomForestClassifier類的實例不具有稱為threshold的屬性。 實際上,您可以使用描述的方式或

setattr(object, 'threshold', 'mean')

但是主要問題似乎是get_params方法檢查BaseEstimator的任何成員的有效屬性的方式:

class BaseEstimator(object):
"""Base class for all estimators in scikit-learn

Notes
-----
All estimators should specify all the parameters that can be set
at the class level in their __init__ as explicit keyword
arguments (no *args, **kwargs).
"""

@classmethod
def _get_param_names(cls):
    """Get parameter names for the estimator"""
    try:
        # fetch the constructor or the original constructor before
        # deprecation wrapping if any
        init = getattr(cls.__init__, 'deprecated_original', cls.__init__)

        # introspect the constructor arguments to find the model parameters
        # to represent
        args, varargs, kw, default = inspect.getargspec(init)
        if not varargs is None:
            raise RuntimeError("scikit-learn estimators should always "
                               "specify their parameters in the signature"
                               " of their __init__ (no varargs)."
                               " %s doesn't follow this convention."
                               % (cls, ))
        # Remove 'self'
        # XXX: This is going to fail if the init is a staticmethod, but
        # who would do this?
        args.pop(0)
    except TypeError:
        # No explicit __init__
        args = []
    args.sort()
    return args

實際上,正如明確指出的那樣,所有估計器都應在其__init__中將可以在類級別設置的所有參數指定為顯式關鍵字參數。

因此,我嘗試將閾值指定為__init__函數中的參數,默認值為'mean'(無論如何,它是當前實現中的默認值)

    def __init__(self,
             n_estimators=10,
             criterion="gini",
             max_depth=None,
             min_samples_split=2,
             min_samples_leaf=1,
             max_features="auto",
             bootstrap=True,
             oob_score=False,
             n_jobs=1,
             random_state=None,
             verbose=0,
             min_density=None,
             compute_importances=None,
             threshold="mean"): # ADD THIS!

然后將此參數的值分配給類的參數。

    self.threshold = threshold # ADD THIS LINE SOMEWHERE IN THE FUNCTION __INIT__

當然,這意味着修改類RandomForestClassifier (在/python2.7/site-packages/sklearn/ensemble/forest.py中),這可能不是最好的方法……但這對我有用! 現在,我可以對不同的閾值參數進行網格搜索(並交叉驗證),從而可以選擇不同數量的特征。

class my_rf_filter(BaseEstimator, TransformerMixin):
def __init__(self,threshold):
    self.threshold = threshold

def fit(self,X,y):
    model = RandomForestClassifier(n_estimators=100, n_jobs=-1, random_state=42, oob_score=False)
    model.fit(X,y)
    self.model = model
    return self

def transform(self,X):
    return self.model.transform(X,self.threshold)

通過將RandomForestClassifier包裝在新類中,它將起作用。

rf_filter = my_rf_filter(threshold='mean')
clf = RandomForestClassifier(n_jobs=-1, random_state=42, oob_score=False)

pipe = Pipeline([("RFF", rf_filter), ("RF", clf)])

# Grid search parameters
rf_n_estimators = [10, 20]
rff_transform = ["median", "mean"] # Search the threshold parameters

estimator = GridSearchCV(pipe,
                         cv = 3, 
                         param_grid = dict(RF__n_estimators = rf_n_estimators,
                                           RFF__threshold = rff_transform))

一個測試例子:

from sklearn import datasets
digits = datasets.load_digits()
X_digits = digits.data
y_digits = digits.target

estimator.fit(X_digits, y_digits)


Out[143]:
GridSearchCV(cv=3,
       estimator=Pipeline(steps=[('RFF', my_rf_filter(threshold='mean')), ('RF', RandomForestClassifier(bootstrap=True, compute_importances=None,
            criterion='gini', max_depth=None, max_features='auto',
            max_leaf_nodes=None, min_density=None, min_samples_leaf=1,
            min_samples_split=2, n_estimators=10, n_jobs=-1,
            oob_score=False, random_state=42, verbose=0))]),
       fit_params={}, iid=True, loss_func=None, n_jobs=1,
       param_grid={'RF__n_estimators': [10, 20], 'RFF__threshold': ['median', 'mean']},
       pre_dispatch='2*n_jobs', refit=True, score_func=None, scoring=None,
       verbose=0)


estimator.grid_scores_

Out[144]:
[mean: 0.89705, std: 0.00912, params: {'RF__n_estimators': 10, 'RFF__threshold': 'median'},
 mean: 0.91597, std: 0.00871, params: {'RF__n_estimators': 20, 'RFF__threshold': 'median'},
 mean: 0.89705, std: 0.00912, params: {'RF__n_estimators': 10, 'RFF__threshold': 'mean'},
 mean: 0.91597, std: 0.00871, params: {'RF__n_estimators': 20, 'RFF__threshold': 'mean'}]

如果您需要在my_rf_filter類中修改RandomForestClassifier的參數,我認為您需要顯式添加它們,即,由於我這樣做失敗,因此model.set_paras(**kwargs)__init__()model.set_paras(**kwargs)使用**kwargs 我認為將n_estimators=200添加到__init__() ,然后進行model.n_estimators = self.n_estimators將起作用。

您可以通過以下技巧避免大多數其他編碼。

首先捕獲估計器的變量參考。 (在這種情況下為“估計器”)您可以在調試過程中查找實際引​​用的超參數名稱。

對於上述問題

pipe = Pipeline([("RFF", rf_filter), ("RF", clf)])
...

param_grid = {"clf__estimator__n_estimators": [10, 20],

}

estimator = GridSearchCV(pipe,
                         cv = 3, 
                         param_grid )

因此,只需將超參數(即max_features)更改為clf__estimator__max_features

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM