文本分类:从评估指标到分类器组合的全面指南
在文本分类领域,我们有多种工具和方法来提高分类的准确性和性能。本文将深入探讨文本分类的各个方面,包括不同分类器的评估、高信息词的计算以及分类器的组合。
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))
- 创建新的特征检测器:
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)
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. 高信息词计算与使用步骤总结
- 计算高信息词 :
- 统计每个单词的频率
word_fd和每个标签下每个单词的条件频率label_word_fd。 - 对于每个标签,计算每个单词的得分。默认使用
nltk.metrics.BigramAssocMeasures.chi_sq()计算得分,公式涉及单词在标签中的频率n_ii、单词在所有标签中的总频率n_ix、该标签下所有单词的总频率n_xi和所有标签下所有单词的总频率n_xx。 - 过滤出得分大于等于
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
- 使用高信息词 :
- 调用
high_information_words函数计算高信息词集合。 - 创建新的特征检测器,过滤出只包含高信息词的特征。
- 使用新的特征检测器获取新的训练和测试特征集。
- 训练和评估分类器。
- 调用
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[训练和评估分类器]
总结
在文本分类任务中,我们可以通过多种方法提高分类性能。首先,选择合适的分类器是关键,不同的分类器有不同的特点和适用场景。其次,使用高信息词可以有效减少噪声和混淆,提高分类器的准确性、精度和召回率,但并非所有分类器都能从高信息词过滤中受益。最后,组合多个分类器可以进一步提高性能,但需要注意分类器的选择和数量。通过合理运用这些方法,我们可以在文本分类任务中取得更好的结果。希望以上内容能为你在文本分类领域的实践提供有价值的参考。
超级会员免费看
1445

被折叠的 条评论
为什么被折叠?



