18、文本分类:从评估指标到分类器组合的全面指南

文本分类:从评估指标到分类器组合的全面指南

在文本分类领域,我们有多种工具和方法来提高分类的准确性和性能。本文将深入探讨文本分类的各个方面,包括不同分类器的评估、高信息词的计算以及分类器的组合。

1. 不同SVM分类器的准确性

在SVM分类器中,不同的实现和默认参数会导致准确性的差异。例如,NuSVC是最准确的SVM分类器,略高于LinearSVC,而SVC的准确性则远低于前两者。你可以通过以下链接了解更多关于这些具体实现的信息: http://scikit - learn.org/stable/modules/svm.html

2. 分类器的评估指标:精度和召回率

除了准确性,精度(Precision)和召回率(Recall)是评估分类器的两个常用指标。为了理解这两个指标,我们需要先了解假阳性(False Positives)和假阴性(False Negatives)。
- 假阳性 :分类器将一个特征集分类为不应有的标签。
- 假阴性 :分类器没有将一个特征集分类为应有的标签。

在二分类器中,这两种错误可能同时发生。例如,将一个电影评论分类为“pos”(积极),而实际上应该是“neg”(消极),这对于“pos”标签来说是假阳性,对于“neg”标签来说是假阴性。

精度是指缺乏假阳性,召回率是指缺乏假阴性。这两个指标通常是相互竞争的,分类器越精确,召回率越低,反之亦然。

以下是计算分类器精度和召回率的代码:

import collections
from nltk import metrics

def precision_recall(classifier, testfeats):
    refsets = collections.defaultdict(set)
    testsets = collections.defaultdict(set)
    for i, (feats, label) in enumerate(testfeats):
        refsets[label].add(i)
        observed = classifier.classify(feats)
        testsets[observed].add(i)
    precisions = {}
    recalls = {}
    for label in classifier.labels():
        precisions[label] = metrics.precision(refsets[label], testsets[label])
        recalls[label] = metrics.recall(refsets[label], testsets[label])
    return precisions, recalls

这个函数接受两个参数:
- 训练好的分类器
- 带标签的测试特征(也称为黄金标准)

以下是一个使用示例:

>>> from classification import precision_recall
>>> nb_precisions, nb_recalls = precision_recall(nb_classifier, test_feats)
>>> nb_precisions['pos']
0.6413612565445026
>>> nb_precisions['neg']
0.9576271186440678
>>> nb_recalls['pos']
0.98
>>> nb_recalls['neg']
0.452

这表明NaiveBayesClassifier类可以正确识别大多数“pos”特征集(高召回率),但也会将许多“neg”特征集分类为“pos”(低精度)。

3. 精度和召回率的计算原理

为了计算精度和召回率,我们需要为每个标签构建两个集合:参考集(Reference Set)和测试集(Test Set)。参考集包含所有正确的值,测试集包含分类器猜测的值。

  • 精度 :两个集合交集的大小除以测试集的大小,即测试集中被正确猜测的百分比。Python代码为: float(len(reference.intersection(test))) / len(test)
  • 召回率 :两个集合交集的大小除以参考集的大小,即参考集中被正确猜测的百分比。Python代码为: float(len(reference.intersection(test))) / len(reference)
4. 不同分类器的精度和召回率

我们对不同的分类器进行了精度和召回率的计算:
| 分类器 | 精度(pos) | 精度(neg) | 召回率(pos) | 召回率(neg) |
| ---- | ---- | ---- | ---- | ---- |
| NaiveBayesClassifier | 0.6413612565445026 | 0.9576271186440678 | 0.98 | 0.452 |
| MaxentClassifier | 0.6456692913385826 | 0.9663865546218487 | 0.984 | 0.46 |
| SklearnClassifier(NuSVC) | 0.9063829787234042 | 0.8603773584905661 | 0.852 | 0.912 |

可以看出,SklearnClassifier(NuSVC)的标签偏差要小得多,这是因为它根据自己的内部模型对特征进行加权。

5. F - 度量

F - 度量是精度和召回率的加权调和平均值,公式为: 1/(alpha/p + (1 - alpha)/r) ,其中alpha是一个权重常数,默认值为0.5。你可以使用 nltk.metrics.f_measure() 来计算F - 度量。它通常用于代替准确性来评估分类器,因为如果精度或召回率很低,F - 度量会反映出来,但准确性不一定。

6. 计算高信息词

高信息词是强烈偏向于单个分类标签的词。消除训练数据中的低信息词(即所有标签共有的词)可以提高准确性、精度和召回率。这是因为只使用高信息词可以减少分类器内部模型的噪声和混淆。

以下是计算高信息词的代码:

from nltk.metrics import BigramAssocMeasures
from nltk.probability import FreqDist, ConditionalFreqDist
import collections

def high_information_words(labelled_words, score_fn=BigramAssocMeasures.chi_sq, min_score=5):
    word_fd = FreqDist()
    label_word_fd = ConditionalFreqDist()
    for label, words in labelled_words:
        for word in words:
            word_fd[word] += 1
            label_word_fd[label][word] += 1
    n_xx = label_word_fd.N()
    high_info_words = set()
    for label in label_word_fd.conditions():
        n_xi = label_word_fd[label].N()
        word_scores = collections.defaultdict(int)
        for word, n_ii in label_word_fd[label].items():
            n_ix = word_fd[word]
            score = score_fn(n_ii, (n_ix, n_xi), n_xx)
            word_scores[word] = score
        bestwords = [word for word, score in word_scores.items() if score >= min_score]
        high_info_words |= set(bestwords)
    return high_info_words

这个函数接受一个参数:一个包含两个元组的列表 [(label, words)] ,其中 label 是分类标签, words 是该标签下出现的单词列表。它返回一个高信息词的集合。

以下是使用高信息词训练和评估分类器的步骤:
1. 计算高信息词:

from featx import high_information_words, bag_of_words_in_set
labels = movie_reviews.categories()
labeled_words = [(l, movie_reviews.words(categories=[l])) for l in labels]
high_info_words = set(high_information_words(labeled_words))
  1. 创建新的特征检测器:
feat_det = lambda words: bag_of_words_in_set(words, high_info_words)
  1. 获取新的训练和测试特征集:
lfeats = label_feats_from_corpus(movie_reviews, feature_detector=feat_det)
train_feats, test_feats = split_label_feats(lfeats)
  1. 训练和评估分类器:
nb_classifier = NaiveBayesClassifier.train(train_feats)
accuracy(nb_classifier, test_feats)
nb_precisions, nb_recalls = precision_recall(nb_classifier, test_feats)
7. 高信息词对不同分类器的影响

我们对不同的分类器使用高信息词特征集进行了评估:
| 分类器 | 准确性 | 精度(pos) | 精度(neg) | 召回率(pos) | 召回率(neg) |
| ---- | ---- | ---- | ---- | ---- | ---- |
| NaiveBayesClassifier | 0.91 | 0.8988326848249028 | 0.9218106995884774 | 0.924 | 0.896 |
| MaxentClassifier | 0.912 | 0.8992248062015504 | 0.9256198347107438 | 0.928 | 0.896 |
| DecisionTreeClassifier | 0.68600000000000005 | 0.6741573033707865 | 0.69957081545064381 | 0.71999999999999997 | 0.65200000000000002 |
| SklearnClassifier(LinearSVC) | 0.86 | 0.871900826446281 | 0.8488372093023255 | 0.844 | 0.876 |

可以看出,并非所有算法都能从高信息词过滤中受益,在某些情况下,准确性可能会下降。

8. 分类器的组合:投票法

组合分类器是提高分类性能的一种方法。最简单的组合多个分类器的方法是使用投票法,选择获得最多投票的标签。为了避免平局,最好使用奇数个分类器,并且每个分类器应该使用不同的算法。

以下是一个使用投票法组合分类器的示例:

import itertools
from nltk.classify import ClassifierI
from nltk.probability import FreqDist

class MaxVoteClassifier(ClassifierI):
    def __init__(self, *classifiers):
        self._classifiers = classifiers
        self._labels = sorted(set(itertools.chain(*[c.labels() for c in classifiers])))

    def labels(self):
        return self._labels

    def classify(self, feats):
        counts = FreqDist()
        for classifier in self._classifiers:
            counts[classifier.classify(feats)] += 1
        return counts.max()

创建 MaxVoteClassifier 时,你需要传入一个要组合的分类器列表。创建后,它的工作方式与其他分类器相同。

>>> from classification import MaxVoteClassifier
>>> mv_classifier = MaxVoteClassifier(nb_classifier, dt_classifier, me_classifier, sk_classifier)
>>> mv_classifier.labels()
['neg', 'pos']
>>> accuracy(mv_classifier, test_feats)
0.894
>>> mv_precisions, mv_recalls = precision_recall(mv_classifier, test_feats)
>>> mv_precisions['pos']
0.9156118143459916
>>> mv_precisions['neg']
0.8745247148288974
>>> mv_recalls['pos']
0.868
>>> mv_recalls['neg']
0.92

这些指标与最好的sklearn分类器以及使用高信息特征的MaxentClassifier和NaiveBayesClassifier类相当。

流程图:文本分类流程

graph LR
    A[数据准备] --> B[训练分类器]
    B --> C[评估分类器]
    C --> D{是否需要优化?}
    D -- 是 --> E[计算高信息词]
    E --> F[创建新特征集]
    F --> B
    D -- 否 --> G[组合分类器]
    G --> H[最终评估]

通过以上步骤,我们可以全面地进行文本分类,从选择合适的分类器到优化特征集,再到组合分类器以提高性能。希望这些方法和技巧能帮助你在文本分类任务中取得更好的结果。

进一步分析与总结

1. 不同分类器性能总结
分类器 原始性能 使用高信息词后性能 性能变化
NaiveBayesClassifier 精度(pos): 0.6413612565445026
精度(neg): 0.9576271186440678
召回率(pos): 0.98
召回率(neg): 0.452
准确性: 0.91
精度(pos): 0.8988326848249028
精度(neg): 0.9218106995884774
召回率(pos): 0.924
召回率(neg): 0.896
整体性能提升,neg精度和pos召回略有下降,但neg召回和pos精度大幅提升
MaxentClassifier 精度(pos): 0.6456692913385826
精度(neg): 0.9663865546218487
召回率(pos): 0.984
召回率(neg): 0.46
准确性: 0.912
精度(pos): 0.8992248062015504
精度(neg): 0.9256198347107438
召回率(pos): 0.928
召回率(neg): 0.896
性能显著提升
DecisionTreeClassifier 未提及原始性能 准确性: 0.68600000000000005
精度(pos): 0.6741573033707865
精度(neg): 0.69957081545064381
召回率(pos): 0.71999999999999997
召回率(neg): 0.65200000000000002
可能由于本身已对高信息特征有一定处理,性能提升不明显
SklearnClassifier(NuSVC) 精度(pos): 0.9063829787234042
精度(neg): 0.8603773584905661
召回率(pos): 0.852
召回率(neg): 0.912
未单独列出使用高信息词后性能,但LinearSVC使用高信息词后准确性从86.4%降至0.86 支持向量机和逻辑回归类算法对高信息词过滤受益较小甚至可能受损
MaxVoteClassifier 准确性: 0.894
精度(pos): 0.9156118143459916
精度(neg): 0.8745247148288974
召回率(pos): 0.868
召回率(neg): 0.92
- 与其他较好分类器性能相当

从这个表格可以清晰地看到不同分类器在原始状态和使用高信息词后的性能变化,有助于我们根据具体需求选择合适的分类器和特征处理方法。

2. 高信息词计算与使用步骤总结
  • 计算高信息词
    1. 统计每个单词的频率 word_fd 和每个标签下每个单词的条件频率 label_word_fd
    2. 对于每个标签,计算每个单词的得分。默认使用 nltk.metrics.BigramAssocMeasures.chi_sq() 计算得分,公式涉及单词在标签中的频率 n_ii 、单词在所有标签中的总频率 n_ix 、该标签下所有单词的总频率 n_xi 和所有标签下所有单词的总频率 n_xx
    3. 过滤出得分大于等于 min_score 的单词,组成高信息词集合。
from nltk.metrics import BigramAssocMeasures
from nltk.probability import FreqDist, ConditionalFreqDist
import collections

def high_information_words(labelled_words, score_fn=BigramAssocMeasures.chi_sq, min_score=5):
    word_fd = FreqDist()
    label_word_fd = ConditionalFreqDist()
    for label, words in labelled_words:
        for word in words:
            word_fd[word] += 1
            label_word_fd[label][word] += 1
    n_xx = label_word_fd.N()
    high_info_words = set()
    for label in label_word_fd.conditions():
        n_xi = label_word_fd[label].N()
        word_scores = collections.defaultdict(int)
        for word, n_ii in label_word_fd[label].items():
            n_ix = word_fd[word]
            score = score_fn(n_ii, (n_ix, n_xi), n_xx)
            word_scores[word] = score
        bestwords = [word for word, score in word_scores.items() if score >= min_score]
        high_info_words |= set(bestwords)
    return high_info_words
  • 使用高信息词
    1. 调用 high_information_words 函数计算高信息词集合。
    2. 创建新的特征检测器,过滤出只包含高信息词的特征。
    3. 使用新的特征检测器获取新的训练和测试特征集。
    4. 训练和评估分类器。
from featx import high_information_words, bag_of_words_in_set
labels = movie_reviews.categories()
labeled_words = [(l, movie_reviews.words(categories=[l])) for l in labels]
high_info_words = set(high_information_words(labeled_words))
feat_det = lambda words: bag_of_words_in_set(words, high_info_words)
lfeats = label_feats_from_corpus(movie_reviews, feature_detector=feat_det)
train_feats, test_feats = split_label_feats(lfeats)
nb_classifier = NaiveBayesClassifier.train(train_feats)
accuracy(nb_classifier, test_feats)
nb_precisions, nb_recalls = precision_recall(nb_classifier, test_feats)
3. 分类器组合的优势与注意事项
  • 优势
    • 多个不同算法的分类器组合可以弥补单个分类器的偏差,提高整体分类性能。例如, MaxVoteClassifier 通过投票机制选择获得最多投票的标签,其性能与较好的sklearn分类器以及使用高信息特征的MaxentClassifier和NaiveBayesClassifier类相当。
  • 注意事项
    • 组合的分类器数量最好为奇数,以避免平局。
    • 不要将性能较差的分类器与性能较好的分类器组合,因为差的分类器可能会拉低整体准确性。

流程图:高信息词处理流程

graph LR
    A[获取带标签单词数据] --> B[统计单词频率和条件频率]
    B --> C[计算每个单词得分]
    C --> D[过滤高信息词]
    D --> E[创建新特征检测器]
    E --> F[获取新特征集]
    F --> G[训练和评估分类器]

总结

在文本分类任务中,我们可以通过多种方法提高分类性能。首先,选择合适的分类器是关键,不同的分类器有不同的特点和适用场景。其次,使用高信息词可以有效减少噪声和混淆,提高分类器的准确性、精度和召回率,但并非所有分类器都能从高信息词过滤中受益。最后,组合多个分类器可以进一步提高性能,但需要注意分类器的选择和数量。通过合理运用这些方法,我们可以在文本分类任务中取得更好的结果。希望以上内容能为你在文本分类领域的实践提供有价值的参考。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值