类型错误:get_params()缺少一个必需的位置参数:'self'。

27

我试图使用Python 3.4中的scikit-learn包进行网格搜索。

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model.logistic import LogisticRegression
from sklearn.pipeline import Pipeline
from sklearn.grid_search import GridSearchCV
import pandas as pd
from sklearn.cross_validation import train_test_split
from sklearn.metrics import precision_score, recall_score, accuracy_score
from sklearn.preprocessing import LabelBinarizer
import numpy as np

pipeline = Pipeline([
    ('vect', TfidfVectorizer(stop_words='english')),
    ('clf', LogisticRegression)
])

parameters = {
    'vect__max_df': (0.25, 0.5, 0.75),
    'vect__stop_words': ('english', None),
    'vect__max_features': (2500, 5000, 10000, None),
    'vect__ngram_range': ((1, 1), (1, 2)),
    'vect__use_idf': (True, False),
    'vect__norm': ('l1', 'l2'),
    'clf__penalty': ('l1', 'l2'),
    'clf__C': (0.01, 0.1, 1, 10)
}

if __name__ == '__main__':
    grid_search = GridSearchCV(pipeline, parameters, n_jobs=-1, verbose=1, scoring='accuracy', cv = 3)
    df = pd.read_csv('SMS Spam Collection/SMSSpamCollection', delimiter='\t', header=None)
    lb = LabelBinarizer()
    X, y = df[1], np.array([number[0] for number in lb.fit_transform(df[0])])
    X_train, X_test, y_train, y_test = train_test_split(X, y)
    grid_search.fit(X_train, y_train)
    print('Best score: ', grid_search.best_score_)
    print('Best parameter set:')
    best_parameters = grid_search.best_estimator_.get_params()
    for param_name in sorted(best_parameters):
        print(param_name, best_parameters[param_name])

然而,它并没有成功运行,错误信息看起来像这样:
Fitting 3 folds for each of 1536 candidates, totalling 4608 fits
Traceback (most recent call last):
  File "/home/xiangru/PycharmProjects/machine_learning_note_with_sklearn/grid search.py", line 36, in <module>
    grid_search.fit(X_train, y_train)
  File "/usr/local/lib/python3.4/dist-packages/sklearn/grid_search.py", line 732, in fit
    return self._fit(X, y, ParameterGrid(self.param_grid))
  File "/usr/local/lib/python3.4/dist-packages/sklearn/grid_search.py", line 493, in _fit
    base_estimator = clone(self.estimator)
  File "/usr/local/lib/python3.4/dist-packages/sklearn/base.py", line 47, in clone
    new_object_params[name] = clone(param, safe=False)
  File "/usr/local/lib/python3.4/dist-packages/sklearn/base.py", line 35, in clone
    return estimator_type([clone(e, safe=safe) for e in estimator])
  File "/usr/local/lib/python3.4/dist-packages/sklearn/base.py", line 35, in <listcomp>
    return estimator_type([clone(e, safe=safe) for e in estimator])
  File "/usr/local/lib/python3.4/dist-packages/sklearn/base.py", line 35, in clone
    return estimator_type([clone(e, safe=safe) for e in estimator])
  File "/usr/local/lib/python3.4/dist-packages/sklearn/base.py", line 35, in <listcomp>
    return estimator_type([clone(e, safe=safe) for e in estimator])
  File "/usr/local/lib/python3.4/dist-packages/sklearn/base.py", line 45, in clone
    new_object_params = estimator.get_params(deep=False)
TypeError: get_params() missing 1 required positional argument: 'self'

我也尝试只使用了。
if __name__ == '__main__':
    pipeline.get_params()

它会给出相同的错误信息。 谁知道该如何解决?

2
这个错误几乎总是误导性的,实际上意味着你正在调用类上的实例方法,而不是实例本身(比如在名为ddict上调用dict.keys()而不是d.keys())。best_estimator_是否给出了一个估计器类型而不是估计器类型的实例?如果是这样,那么问题就出在这里;你必须通过调用该类型(使用适当的参数)来构造一个估计。 - abarnert
2个回答

55

这个错误几乎总是误导性的,实际上意味着你在类上调用实例方法,而不是实例本身(就像在名为d的字典上调用dict.keys()而不是d.keys()一样)。*

这正是这里正在发生的事情。文档暗示best_estimator_属性(就像初始化器的estimator参数一样)不是估算器实例,而是估算器类型,“该类型的对象将为每个网格点实例化。”

因此,如果你想调用方法,你必须构造该类型的某个特定网格点的对象。

然而,从快速浏览文档来看,如果你想获取返回最佳分数的最佳估算器实例使用的参数,那么这不就是best_params_吗?(我很抱歉这部分有点猜测...)


对于Pipeline调用,您肯定有一个实例。该方法的唯一文档是一个参数规范,显示它需要一个可选参数deep。但在底层,它可能会将get_params()调用转发到其某个属性。并且使用('clf', LogisticRegression),看起来您正在使用类LogisticRegression构建它,而不是该类的实例,因此如果它最终转发到该类,那就可以解释问题了。


* 出现错误提示“missing 1 required positional argument: 'self'”,而不是“必须在实例上调用”之类的原因是,在Python中,d.keys()实际上被转换为dict.keys(d),有时候显式地这样调用是合法的(有时也很有用),所以Python无法告诉你dict.keys()是非法的,只能告诉你缺少了self参数。

错误发生在 grid_search.fit(X_train, y_train) 这一行。它没有执行拟合操作。 - Xiangru Lian
@abarnert 在类似的情境下,您能否请看一下这个问题?https://stackoverflow.com/questions/63533647/gridsearchcv-with-scoring-function-and-refit-parameter - Soyol

28
我最终解决了这个问题,原因正如abarnert所说的那样。
首先,我尝试了:
pipeline = LogisticRegression()

parameters = {
    'penalty': ('l1', 'l2'),
    'C': (0.01, 0.1, 1, 10)
}

它运作良好。

基于这种直觉,我修改了流程如下:

pipeline = Pipeline([
    ('vect', TfidfVectorizer(stop_words='english')),
    ('clf', LogisticRegression())
])

注意在 LogisticRegression 后面有一对圆括号()。 这次它会正常工作。


3
() 表示你正在 调用 它。调用一个类会构造该类的实例。这正是你必须做的,就像我在我的回答中所解释的那样。 - abarnert
@abarnert 谢谢!我明白你的想法了。 - Xiangru Lian
我遇到了类似的问题,使用lda = discriminant_analysis.LinearDiscriminantAnalysis()实例化后忘记加上()。 - Surabhi Amit Chembra
1
如果@abarnert给出了正确的解决方案,我认为适当的做法是选择他的答案作为解决方案,而不是选择自己的。 - ryanjdillon
@abarnert的回答也帮助了我!为什么不将其标记为原始问题的答案,而不是这个呢? - Ilya Chernov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接