【问题标题】:I'm not sure how to interpret accuracy of this classification with Scikit Learn我不确定如何使用 Scikit Learn 解释此分类的准确性
【发布时间】:2015-07-31 04:30:37
【问题描述】:

我正在尝试使用 Scikit Learn 使用此处显示的方法对文本数据进行分类。 (http://scikit-learn.org/stable/tutorial/text_analytics/working_with_text_data.html) 除了我正在加载我自己的数据集。

我得到了结果,但我想找到分类结果的准确性。

    from sklearn.datasets import load_files

    text_data = load_files("C:/Users/USERNAME/projects/machine_learning/my_project/train", description=None, categories=None, load_content=True, shuffle=True, encoding='latin-1', decode_error='ignore', random_state=0)

    from sklearn.pipeline import Pipeline
    from sklearn.linear_model import SGDClassifier
    text_clf = Pipeline([('vect', CountVectorizer()),
                        ('tfidf', TfidfTransformer()),
                        ('clf', LinearSVC(loss='hinge', penalty='l2',
                                                random_state=42)),
    ])

    _ = text_clf.fit(text_data.data, text_data.target)

    docs_new = ["Some test sentence here.",]

    predicted = text_clf.predict(docs_new)
    print np.mean(predicted == text_data.target) 

    for doc, category in zip(docs_new, predicted):
        print('%r => %s' % (doc, text_data.target_names[predicted]))

在这里,我得到的 np.mean 预测值为 0.566。

如果我尝试:

twenty_test = load_files("C:/Users/USERNAME/projects/machine_learning/my_project/testing", description=None, categories=None, load_content=True, shuffle=True, encoding='latin-1', decode_error='ignore', random_state=0)
docs_test = twenty_test.data
predicted = text_clf.predict(docs_test)
np.mean(predicted == twenty_test.target)

现在它打印为 1。

我不明白这是如何工作的,不明白 np.mean 到底是什么,以及为什么它在使用相同的数据进行训练时会显示不同的结果。

“train”文件夹有大约 15 个文档,text 文件夹也有大约 15 个文档,以防万一。总的来说,我对 Scikit Learn 和机器学习非常陌生,因此非常感谢任何帮助。谢谢!

【问题讨论】:

  • 你的测试文件是什么样的?同时打印预测和二十测试目标。

标签: python machine-learning scikit-learn classification text-classification


【解决方案1】:
text_data = load_files("C:/Users/USERNAME/projects/machine_learning/my_project/train", ...)

根据the documentation,该行将您的文件内容从C:/Users/USERNAME/projects/machine_learning/my_project/train 加载到text_data.data。它还将每个文档的目标标签(由它们的整数索引表示)加载到text_data.target。所以text_data.data 应该是一个字符串列表,text_data.target 应该是一个整数列表。标签源自文件所在的文件夹。您的解释听起来好像您在 C:/.../train/C:/.../test/ 中没有任何子文件夹,这可能会产生问题(例如,所有标签都相同)。

from sklearn.pipeline import Pipeline
from sklearn.linear_model import SGDClassifier
text_clf = Pipeline([('vect', CountVectorizer()),
                    ('tfidf', TfidfTransformer()),
                    ('clf', LinearSVC(loss='hinge', penalty='l2',
                                            random_state=42)),
])

_ = text_clf.fit(text_data.data, text_data.target)

以上行是在您的示例文档上训练(在.fit() 中)一个分类器。非常粗略地说,您是在告诉分类器 (LinearSVC) 哪些单词出现在哪些文档中的频率(CountVectorizerTfidfTransformer)以及每个文档具有哪些标签(text_data.target)。然后,您的分类器会尝试学习一个规则,该规则基本上将这些词频(TF-IDF 值)映射到标签(例如,dogcat 强烈指示标签 animal)。

docs_new = ["Some test sentence here.",]
predicted = text_clf.predict(docs_new)

在使用示例数据训练分类器后,您提供一个全新的文档,并让您的分类器根据它所学到的内容预测最适合该文档的标签。 predicted 应该是只有一个元素的标签(索引)列表(因为你有一个文档),例如。 G。 [5].

print np.mean(predicted == text_data.target)

在这里,您将预测列表(1 个元素)与训练数据中的标签列表(15 个元素)进行比较,然后取结果的平均值。这没有多大意义,因为列表大小不同,而且您的新示例文档与训练标签没有任何关系。 Numpy 可能会将您的预测标签(例如5)与text_data.target 中的每个元素进行比较。这将创建一个类似[False, False, False, True, False, True, ...] 的列表,np.mean 将其解释为[0, 0, 0, 1, 0, 1, ...],因此平均值为1/15 * (0+0+0+1+0+1+...)

你应该做的是e。 G。类似:

docs_new = ["Some test sentence here."]
docs_new_labels = [1] # correct label index of the document

predicted = text_clf.predict(docs_new)
print np.mean(predicted == docs_new_labels) 

至少您不应该与您的训练标签进行比较。 请注意,如果np.mean 返回1,则所有文档都正确分类。对于您的测试数据集,这似乎正在发生。确保您的测试和训练数据文件实际上是不同的,因为 100% 的准确率并不常见(但可能是您的训练文件数量过少造成的)。在旁注中,请注意当前未使用标记化,因此对于您的分类器 herehere. 将是完全不同的词。

【讨论】:

  • 谢谢!这对我来说非常有用并澄清了很多事情! (1) 我在C:/.../train/C:/.../testing/ 中有文件夹。它们都具有相同的文件夹轮廓,例如。 “体育新闻”和“文化新闻”,顺序与here 相同。 (2)np.mean(predicted == docs_new_labels),就像你说的,返回 1.0。这是否意味着 np.mean 是算法对预测准确性水平的置信度? (4) 你能否进一步扩展关于标记化的旁注?再次感谢!
  • 很抱歉,如果这是一个完全不同的问题,但是检查算法是否真的表现良好的最佳方法是什么?
  • 使用np.mean 只是告诉您分类器在测试集上正确的频率(例如,0.5 = 每秒一次)。标记化将您的内容转换为更多标记。一个典型的规则是分开标点符号,例如here.(一个罕见词)将变为here .(两个常用词)。您可以为此使用 nltk,请参阅 here。测试算法的一种好方法是收集大量独特的测试内容,然后使用 metrics.classification_report,就像 Harpal 的回答一样。
【解决方案2】:

precict() 返回给定未知文本的预测类标签数组。见源here

docs_new = ['God is love', 'OpenGL on the GPU is fast', 'java', '3D', 'Cinema 4D']
predicted = clf.predict(X_new_tfidf)
print predicted
for doc, category in zip(docs_new, predicted):
    print('%r => %s' % (doc, twenty_train.target_names[category]))

[3 1 2 1 1]
'God is love' => soc.religion.christian
'OpenGL on the GPU is fast' => comp.graphics
'java' => sci.med
'3D' => comp.graphics
'Cinema 4D' => comp.graphics

如您所见,predicted 返回一个数组。数组中的数字对应于标签的索引,这些索引在随后的 for 循环中被访问。

当您执行np.mean 时,这是为了确定分类器的准确性,并且不适用于您的第一个示例,因为文本"Some text here" 没有标签。不过,这段文本可以用来预测它属于哪个标签。这可以通过更改在您的脚本中实现:

for doc, category in zip(docs_new, predicted):
    print('%r => %s' % (doc, text_data.target_names[predicted]))

到:

for doc, category in zip(docs_new, predicted):
    print('%r => %s' % (doc, text_data.target_names[category]))

当您第二次调用 np.mean 返回 1 时,这意味着分类器能够以 100% 的准确度将未见过的文档预测为正确的标签。因为,twenty_test 数据也有标签信息。

要获得有关分类器准确性的更多信息,您可以:

from sklearn import metrics
print(metrics.classification_report(twenty_test.target, predicted,
    target_names=twenty_test.target_names)) 


                        precision    recall  f1-score   support

           alt.atheism       0.95      0.81      0.87       319
         comp.graphics       0.88      0.97      0.92       389
               sci.med       0.94      0.90      0.92       396
soc.religion.christian       0.90      0.95      0.93       398

           avg / total       0.92      0.91      0.91      1502

如果你想要一个混淆矩阵,你可以:

metrics.confusion_matrix(twenty_test.target, predicted)

array([[258,  11,  15,  35],
       [  4, 379,   3,   3],
       [  5,  33, 355,   3],
       [  5,  10,   4, 379]])

【讨论】:

    猜你喜欢
    • 2017-08-20
    • 1970-01-01
    • 2019-11-18
    • 2019-10-30
    • 2014-11-24
    • 2019-06-07
    • 2017-02-07
    • 2015-03-20
    • 2015-06-26
    相关资源
    最近更新 更多