GridsearchCV:尝试在参数中传递 lambda 时无法腌制函数错误

Posted

技术标签:

【中文标题】GridsearchCV:尝试在参数中传递 lambda 时无法腌制函数错误【英文标题】:GridsearchCV: can't pickle function error when trying to pass lambda in parameter 【发布时间】:2018-11-15 05:47:57 【问题描述】:

我在 *** 和其他地方进行了广泛的研究,但似乎无法找到以下问题的答案。

我正在尝试修改函数的参数,该参数本身就是 GridSearchCV function of sklearn. More specifically, I want to change parameters (herepreserve_case = False) inside thecasual_tokenizefunction that is passed to the parametertokenizerof the functionCountVectorizer` 中的参数。

具体代码如下:

from sklearn.datasets import fetch_20newsgroups
from sklearn.pipeline import Pipeline
from sklearn.naive_bayes import MultinomialNB
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.model_selection import GridSearchCV
from nltk import casual_tokenize

从 20newsgroup 生成虚拟数据

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

创建分类管道。 请注意,可以使用lambda 修改标记器。我想知道是否还有其他方法可以做到这一点,因为它不适用于 GridSearchCV

text_clf = Pipeline([('vect',
                      CountVectorizer(tokenizer=lambda text:
                                     casual_tokenize(text, 
                                     preserve_case=False))),
                     ('tfidf', TfidfTransformer()),
                     ('clf', MultinomialNB()),
                    ])

text_clf.fit(twenty_train.data, twenty_train.target) # this works fine

然后我想将CountVectorizer 的默认标记器与 nltk 中的进行比较。请注意,我问这个问题是因为我想比较多个标记器,每个标记器都有需要指定的特定参数。

parameters = 'vect':[CountVectorizer(),
                       CountVectorizer(tokenizer=lambda text:
                                       casual_tokenize(text, 
                                       preserve_case=False))]

gs_clf = GridSearchCV(text_clf, parameters, n_jobs=-1, cv=5)
gs_clf = gs_clf.fit(twenty_train.data[:100], twenty_train.target[:100])

gs_clf.fit 给出以下错误:PicklingError: Can't pickle at 0x1138c5598>: attribute lookup on ma​​in failed

所以我的问题是: 1) 有谁知道如何专门用GridSearchCV 处理这个问题。 2)有没有更好的pythonic方法来处理将参数传递给也将是参数的函数?

【问题讨论】:

【参考方案1】:

1) 有没有人知道如何专门处理这个问题 GridSearchCV。

您可以使用partial 代替lambda

from functools import partial
from sklearn.externals.joblib import dump

def add(a, b):
    return a + b

plus_one = partial(add, b=1)
plus_one_lambda = lambda a: a + 1
dump(plus_one, 'add.pkl')          # No problem
dump(plus_one_lambda, 'add.pkl')   # Pickling error

对于您的情况:

tokenizer=partial(casual_tokenize, preserve_case=False)

2) 有没有更好的 Pythonic 方式来处理传递参数 到一个也将是参数的函数?

我认为使用lambdapartial 都是“pythonic 方式”。

这里的问题是GridSearchCV 使用多处理。这意味着它可能会启动多个进程,它必须将一个进程中的参数序列化并将它们传递给其他进程(然后目标进程反序列化以获得相同的参数)。

GridSearchCV 使用joblib 进行多处理/序列化。 Joblib 无法处理 lambda 函数。

【讨论】:

很好的答案,谢谢!关于joblib的解释非常有用。

以上是关于GridsearchCV:尝试在参数中传递 lambda 时无法腌制函数错误的主要内容,如果未能解决你的问题,请参考以下文章

如何将最佳参数(使用 GridSearchCV)从管道传递到另一个管道

GridSearchCV 对平均绝对误差的评分

K-Means GridSearchCV 超参数调优

Gridsearchcv 与贝叶斯优化

尝试使用 Gridsearchcv 时出现内存错误

在 python 中使用 gridsearchcv 进行梯度提升分类器的参数调整