首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么`best_estimator_.get_params()`不同意`best_params_`

为什么`best_estimator_.get_params()`不同意`best_params_`
EN

Stack Overflow用户
提问于 2019-12-10 07:57:05
回答 1查看 335关注 0票数 0

我正在尝试一些scikit-learn对象,在尝试调优超参数时,我偶然发现了以下结果。这段代码的输出

代码语言:javascript
复制
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import GridSearchCV
from sklearn.naive_bayes import MultinomialNB
from sklearn.pipeline import Pipeline


class NaiveBayesClassifier(Pipeline):
    def __init__(self):
        super().__init__(
            [("tfidf", TfidfVectorizer()), ("clf", MultinomialNB()),]
        )

    def tune(self, data, min_df, max_df, max_features):
        gs = GridSearchCV(
            estimator=self,
            param_grid={
                "tfidf__max_df": max_df,
                "tfidf__min_df": min_df,
                "tfidf__max_features": max_features,
            },
            verbose=10,
        )

        return gs.fit(*data)


if __name__ == "__main__":
    from sklearn.datasets import fetch_20newsgroups

    categories = ["alt.atheism", "soc.religion.christian", "comp.graphics", "sci.med"]
    twenty_train = fetch_20newsgroups(
        subset="train", categories=categories, shuffle=True, random_state=42
    )

    nb = NaiveBayesClassifier()

    tuned_model = nb.tune(
        (twenty_train.data, twenty_train.target),
        min_df=[0, 0.1],
        max_df=[0.9, 1],
        max_features=[2_000, 5_000],
    )

    print(tuned_model.best_score_)
    for k, v in tuned_model.best_params_.items():
        print(f"{v}    <>    {tuned_model.best_estimator_.get_params()[k]}")

如下所示

代码语言:javascript
复制
0.9437278025233994
0.9    <>    1.0
5000    <>    None
0    <>    1

查看网格搜索生成的输出,我可以看到左侧的参数确实产生了5次折叠的平均分数。因此,tuned_model.best_params_似乎是我所期望的。但是,best_estimator_的参数只是默认参数。

这是什么原因造成的?Pipeline类有一个set_params方法,它似乎对tuned_model.best_estimator_.set_params(tuned_model.best_params_)做了正确的事情(当然,现在只有参数是最优的,而模型不是)。

EN

回答 1

Stack Overflow用户

发布于 2019-12-10 09:37:42

看起来子类化不能很好地处理sklearn.base.clone,因为在子类上调用get_params的结果与在Pipeline的实际实例上调用相同方法的结果不同(从0.22版开始)。

为了获得正确的sklearn估计器,__init__方法必须将参数声明为显式关键字参数。override def __init__(self)有效地创建了一个不带参数的估计器。这就解释了为什么get_params(deep=False)返回一个空的dict

下面的子类起作用

代码语言:javascript
复制
class NaiveBayesClassifier(Pipeline):
    def __init__(self, steps=[], memory=None, verbose=False):
        super().__init__(
            steps or [("tfidf", TfidfVectorizer()), ("clf", MultinomialNB())]
        )

    def tune(self, data, min_df, max_df, max_features):
        gs = GridSearchCV(
            estimator=self,
            param_grid={
                "tfidf__max_df": max_df,
                "tfidf__min_df": min_df,
                "tfidf__max_features": max_features,
            },
            verbose=10,
        )

        return gs.fit(*data)

虽然这现在可以正常工作,但__init__的签名是“丑陋的”,因为原则上它不应该接受任何参数。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59258339

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档