我需要构建我的自定义转换器,在管道中使用它并使用GridSearchCV评估它调整该管道的参数。
我设法按照here的建议实现了简单的自定义变换器,但是 尝试使用内部估算器实现变换器时出现的问题,并在GridSearchCV中使用此构造。在我看来,我自己找不到答案,因为我不完全理解搜索方法的微妙之处,如(网格/随机化)SearchCV和set_params。
"用Python简介ML" 一书描述了GridSearchCV逻辑而不是天真:
...iterating over each parameters combination...
init estimator
fit estimator
evaluate
但这种天真的方法无法回答我的问题。为了澄清我的问题,让我们来看看。看看这个案例:
class OuterTransformer(BaseEstimator, TransformerMixin):
_options = {'std':StandardScaler(),'mm':MinMaxScaler()}
def __init__(self, option='std'):
...
对我来说,主要的问题是"我在哪里选择内部估算器的逻辑?" 。根据上面提到的帖子,这应该是这样的:
def __init__(self, option='std'):
self.option = option
def fit(self, data, y=None):
self.option = self._options[option]
...
另一方面,常识要求GridSearch在调用 fit 之前必须传递参数来初始化内部估算器,因此应在 __ init __ 中选择内部估算器。 / p>
似乎第一种方式工作正常,但我无法理解为什么。 可以请有人向我解释这个现象吗?
答案 0 :(得分:1)
看起来我理解了估算器参数的初始化和重新初始化的逻辑。这有助于回答我的问题:
类字段必须使用传递给构造函数的原始值进行初始化,而不是使用它们的某些“衍生物”进行初始化,因为每个初始化估算器,scikit调用 __ init __ ,传递在CV启动之前通过 get_params 方法从实例中提取的参数。
get_params 的本质是它扫描类的方法 __ init __ 的签名,并从名称对应于名称的估计器字段的实例中提取 __ init __ 的参数(当然除了 self )。
因此,如果我们将“派生”值写入 __ init __ 方法中的字段,这些“派生”值将转移到下一个重新初始化,这意味着一切都会失败。
class OuterTransformer(BaseEstimator, TransformerMixin):
_options = {'std':StandardScaler(),'mm':MinMaxScaler()}
# good init- all fine
def __init__(self, option='std'):
self.option = option
# bad init - will not work, because option is not an 'original' parameter.
def __init__(self, option='std'):
self.option = self._options[option]