【问题标题】:How to solve a NotImplementedError from nltk.classify ClassifierI?如何解决来自 nltk.classify ClassifierI 的 NotImplementedError?
【发布时间】:2018-03-27 00:14:28
【问题描述】:

我是编程新手,但我一遍又一遍地查看我的代码,看不到任何错误。我不知道如何继续进行,因为无论我尝试什么都会弹出此错误。我将在这里发布完整的代码。

任何帮助将不胜感激,谢谢!

import nltk
import random
from nltk.corpus import movie_reviews
import pickle
from nltk.classify.scikitlearn import SklearnClassifier
from sklearn.naive_bayes import MultinomialNB,BernoulliNB
from sklearn.linear_model import LogisticRegression, SGDClassifier
from sklearn.svm import SVC, LinearSVC, NuSVC
from nltk.classify import ClassifierI
from statistics import mode 

class VoteClassifier(ClassifierI):
    def __init__(self, *classifiers):
        self._classifiers = classifiers

        def classify(self, features):
            votes = []
            for c in self._classifiers:
                v = c.classify(features)
                votes.append(v)
            return mode(votes)


        def confidence(self, features):
            votes = []
            for c in self._classifiers:
                v = c.classify(features)
                votes.append(v)


            choice_votes = votes.count(mode(votes))
            conf = choice_votes / len(votes)
            return conf


documents = [(list(movie_reviews.words(fileid)), category)
             for category in movie_reviews.categories()
             for fileid in movie_reviews.fileids(category)]

random.shuffle(documents)

all_words = []

for w in movie_reviews.words():
        all_words.append(w.lower())

all_words = nltk.FreqDist(all_words)

word_features = list(all_words.keys())[:3000]

def find_features(document):
    words = set(document)
    features = {}
    for w in word_features:
        features[w] = (w in words)

    return features

featuresets = [(find_features(rev), category) for (rev, category) in documents]

training_set = featuresets[:1900]
testing_set = featuresets[1900:]

# classifier = nltk.NaiveBayesClassifier.train(training_set)
classifier_f = open("naivebayes.pickle", "rb")
classifier = pickle.load(classifier_f)
classifier_f.close()

print("Original NaiveBayes accuracy percent:",(nltk.classify.accuracy(classifier, testing_set))*100)
classifier.show_most_informative_features(10)

MNB_classifier = SklearnClassifier(MultinomialNB())
MNB_classifier.train(training_set)
print("MNB_classifier accuracy percent:", (nltk.classify.accuracy(MNB_classifier, testing_set))*100)

BernoulliNB_classifier = SklearnClassifier(BernoulliNB())
BernoulliNB_classifier.train(training_set)
print("BernoulliNB_classifier accuracy percent:", (nltk.classify.accuracy(BernoulliNB_classifier, testing_set))*100)

LogisticRegression_classifier = SklearnClassifier(LogisticRegression())
LogisticRegression_classifier.train(training_set)
print("LogisticRegression_classifier accuracy percent:", (nltk.classify.accuracy(LogisticRegression_classifier, testing_set))*100)

SGDClassifier_classifier = SklearnClassifier(SGDClassifier())
SGDClassifier_classifier.train(training_set)
print("SGDClassifier_classifier accuracy percent:", (nltk.classify.accuracy(SGDClassifier_classifier, testing_set))*100)

##SVC_classifier = SklearnClassifier(SVC())
##SVC_classifier.train(training_set)
##print("SVC_classifier accuracy percent:", (nltk.classify.accuracy(SVC_classifier, testing_set))*100)

LinearSVC_classifier = SklearnClassifier(LinearSVC())
LinearSVC_classifier.train(training_set)
print("LinearSVC_classifier accuracy percent:", (nltk.classify.accuracy(LinearSVC_classifier, testing_set))*100)

NuSVC_classifier = SklearnClassifier(NuSVC())
NuSVC_classifier.train(training_set)
print("NuSVC_classifier accuracy percent:", (nltk.classify.accuracy(NuSVC_classifier, testing_set))*100)


voted_classifier = VoteClassifier(classifier,
                                  NuSVC_classifier,
                                  LinearSVC_classifier,
                                  SGDClassifier_classifier,
                                  MNB_classifier,
                                  BernoulliNB_classifier,
                                  LogisticRegression_classifier)

print("voted_classifier accuracy percent:", (nltk.classify.accuracy(voted_classifier, testing_set))*100)

我还尝试在顶部的类上引发 NotImplementedError 异常,但它并没有改变 Python 中的输出。

这是错误:

Traceback (most recent call last):
  File "code/test.py", line 109, in <module>
    print("voted_classifier accuracy percent:", (nltk.classify.accuracy(voted_classifier, testing_set))*100)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/nltk/classify/util.py", line 87, in accuracy
    results = classifier.classify_many([fs for (fs, l) in gold])
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/nltk/classify/api.py", line 77, in classify_many
    return [self.classify(fs) for fs in featuresets]
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/nltk/classify/api.py", line 56, in classify
    raise NotImplementedError()
NotImplementedError

【问题讨论】:

  • 你所依赖的库(nltk)是generating the error。您需要在不调用该函数的情况下使用该库,或者在他们的 GitHub 页面上提出问题。
  • 是否可以覆盖错误?该文档有一个“如果被覆盖的行”github.com/nltk/nltk/blob/develop/nltk/classify/api.py#L53
  • 看来self.classify_many 只是一个占位符方法,需要在其他地方覆盖。我不熟悉这个库,但我怀疑如果你只是覆盖错误它会起作用。
  • 您的 VoteClassifier 类是 ClassifierI 的子类,ClassifierI 是一个抽象基类。它的目的是在制作自己的分类器和执行接口检查时作为指南。检查 ClassifierI 的来源。 github.com/nltk/nltk/blob/develop/nltk/classify/api.py#L27 ClassifierI 中引发 NotImplementedError 的任何方法都必须在 VoteClassifier 中实现。
  • 是的@101 是对的。看起来classify vs classify_many 发生了一些类似圆形意大利面的事情 =(

标签: python nltk


【解决方案1】:

正如 cmets 中所述,ClassiferI api 中有一些像意大利面条一样的糟糕代码,当被覆盖时,classify 会调用 classify_many。考虑到ClassifierINaiveBayesClassifier 对象紧密相关,这可能不是一件坏事。

但是对于 OP 中的特殊用途,这里的意大利面条代码不受欢迎。

TL;DR

看看https://www.kaggle.com/alvations/sklearn-nltk-voteclassifier

长期

从追溯来看,错误是从nltk.classify.util.accuracy() 调用ClassifierI.classify() 开始的。

ClassifierI.classify() 通常用于对 ONE 文档进行分类,输入是具有二进制值的特征集字典。

ClassifierI.classify_many() 应该对 MULTIPLE 文档进行分类,输入是特征集字典列表及其二进制值。

因此,快速破解方法是覆盖accuracy() 函数的方式,以便VotedClassifier 不会依赖于classify()classify_many()ClassifierI 定义。这也意味着我们不会从ClassifierI 继承。恕我直言,如果您不需要classify()以外的其他功能,则无需继承ClassifierI可能带来的包袱:

def my_accuracy(classifier, gold):
    documents, labels = zip(*gold)
    predictions = classifier.classify_documents(documents)
    correct = [y == y_hat for y, y_hat in zip(labels, predictions)]
    if correct:
        return sum(correct) / len(correct)
    else:
        return 0

class VotraClassifier:
    def __init__(self, *classifiers):
        self._classifiers = classifiers

    def classify_documents(self, documents):
        return [self.classify_many(doc) for doc in documents]

    def classify_many(self, features):
        votes = []
        for c in self._classifiers:
            v = c.classify(features)
            votes.append(v)
        return mode(votes)

    def confidence(self, features):
        votes = []
        for c in self._classifiers:
            v = c.classify(features)
            votes.append(v)

        choice_votes = votes.count(mode(votes))
        conf = choice_votes / len(votes)
        return conf

现在如果我们用新的VotedClassifier 对象调用新的my_accuracy()

voted_classifier = VotraClassifier(nltk_nb, 
                                  NuSVC_classifier,
                                  LinearSVC_classifier,
                                  SGDClassifier_classifier,
                                  MNB_classifier,
                                  BernoulliNB_classifier,
                                  LogisticRegression_classifier)

my_accuracy(voted_classifier, testing_set)

[出]:

0.86

注意:在打乱文档然后拿出一组来测试分类器准确性时,存在一定的随机性。

我的建议是做以下而不是简单的random.shuffle(documents)

  • 使用各种随机种子重复实验。
  • 对于每个随机种子,进行 10 倍交叉验证。

【讨论】:

  • 感谢您的帮助! :)
猜你喜欢
  • 1970-01-01
  • 2011-07-14
  • 1970-01-01
  • 1970-01-01
  • 2019-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-21
相关资源
最近更新 更多