我正在尝试使用SklearnClassifier
和ClassifierBasedPOSTagger
构建自己的基于词性标注的分类器。我已经尝试过的代码如下:
from nltk.corpus import treebank
nltk.download('treebank')
data = treebank.tagged_sents()
train_data = data[:3500]
test_data = data[3500:]
from nltk.classify import SklearnClassifier
from sklearn.naive_bayes import BernoulliNB
from nltk.tag.sequential import ClassifierBasedPOSTagger
bnb = SklearnClassifier(BernoulliNB())
bnb_tagger = ClassifierBasedPOSTagger(train=train_data,
classifier_builder=bnb.train)
# evaluate tagger on test data and sample sentence
print(bnb_tagger.evaluate(test_data))
# see results on our previously defined sentence
print(bnb_tagger.tag(nltk.word_tokenize(sentence)))
这段代码产生了以下错误:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
C:\Users\ABDULL~1.IMR\AppData\Local\Temp/ipykernel_6580/266992580.py in <module>
4
5 bnb = SklearnClassifier(BernoulliNB())
----> 6 bnb_tagger = ClassifierBasedPOSTagger(train=train_data,
7 classifier_builder=bnb.train)
8
~\Miniconda3\envs\nlp_course\lib\site-packages\nltk\tag\sequential.py in __init__(self, feature_detector, train, classifier_builder, classifier, backoff, cutoff_prob, verbose)
637
638 if train:
--> 639 self._train(train, classifier_builder, verbose)
640
641 def choose_tag(self, tokens, index, history):
~\Miniconda3\envs\nlp_course\lib\site-packages\nltk\tag\sequential.py in _train(self, tagged_corpus, classifier_builder, verbose)
673 if verbose:
674 print("Training classifier ({} instances)".format(len(classifier_corpus)))
--> 675 self._classifier = classifier_builder(classifier_corpus)
676
677 def __repr__(self):
~\Miniconda3\envs\nlp_course\lib\site-packages\nltk\classify\scikitlearn.py in train(self, labeled_featuresets)
110
111 X, y = list(zip(*labeled_featuresets))
--> 112 X = self._vectorizer.fit_transform(X)
113 y = self._encoder.fit_transform(y)
114 self._clf.fit(X, y)
~\Miniconda3\envs\nlp_course\lib\site-packages\sklearn\feature_extraction\_dict_vectorizer.py in fit_transform(self, X, y)
288 Feature vectors; always 2-d.
289 """
--> 290 return self._transform(X, fitting=True)
291
292 def inverse_transform(self, X, dict_type=dict):
~\Miniconda3\envs\nlp_course\lib\site-packages\sklearn\feature_extraction\_dict_vectorizer.py in _transform(self, X, fitting)
233 if feature_name in vocab:
234 indices.append(vocab[feature_name])
--> 235 values.append(self.dtype(v))
236
237 indptr.append(len(indices))
TypeError: float() argument must be a string or a number, not 'NoneType'
如何正确实现?
2条答案
按热度按时间y3bcpkx11#
这是一个scikit-learn的bug。让我向您展示:
ClassifierBasedPOSTagger
(及其超类ClassifierBasedTagger
)使用了一个feature_detector
方法,该方法给定一些参数(标记、索引、历史记录)会产生一个类似于以下的字典:在某些情况下,例如对于句子中的第一个单词,前一个标签根本不存在,即
None
。例如,如果我们取样训练句子:那么
ClassifierBasedPOSTagger
将在_train
中调用feature_detector
,产生:因此,从特征名称到特征值的Map具有预期的类型
Dict[str, Optional[str]]
。这个Map沿着链传递,到达
sklearn\feature_extraction\_dict_vectorizer.py
,到达_transform
DictVectorizer
的方法。使用像最后一个示例中的x
特征字典,以下代码段将运行:https://github.com/scikit-learn/scikit-learn/blob/e64714637d8cc9f4724ae21ea500e4bdc57b0a39/sklearn/feature_extraction/_dict_vectorizer.py#L223-L255
第227行负责处理特征值为
None
的情况,将特征名称设置为例如"prevprevtag"
。然而,在第255行,我们的特征值的默认值dtype
被取走,这产生了np.float64(None)
。这会抛出您正在经历的TypeError。简而言之-scikit-learn的
_transform
方法在输入参数包含Map到None时失败。我的建议是将其报告为问题。您可以在此消息上链接。
也许在此期间,您可以使用以下代码片段:
这将防止特征值为
None
,而bug仍然存在。相反,它使用'None'
。或者,您可以想出要使用的任何令牌来替换None
,例如key: value if value else 'my_custom_value_which_represents_none'
。我没有时间为您实际训练更大的东西,所以我快速地用三个句子进行了训练:
这输出:
(显然这个评估很糟糕,但重点是它不再崩溃了)
快乐标记,
ejk8hzay2#
@larsmans - 如果你对scikit-learn中可能存在的bug有任何看法