文本分类:从精度评估到分类器组合
1. 不同SVM分类器的准确性
在文本分类任务中,不同的SVM分类器具有不同的准确性。例如,NuSVC是最准确的SVM分类器,略高于LinearSVC,而SVC的准确性则远低于前两者。这些准确性差异是由不同的算法实现和默认参数导致的。你可以通过以下链接了解这些具体实现的更多信息: http://scikit - learn.org/stable/modules/svm.html 。
2. 分类器的精度和召回率
2.1 概念理解
除了准确性,还有许多其他指标用于评估分类器,其中最常见的两个指标是精度(Precision)和召回率(Recall)。在理解这两个指标之前,我们需要先了解假阳性(False Positives)和假阴性(False Negatives)的概念。
- 假阳性:当分类器将一个特征集分类为某个标签,但实际上该特征集不应属于该标签时,就会出现假阳性。
- 假阴性:当分类器没有将一个特征集分类为它应该属于的标签时,就会出现假阴性。
例如,一个分类器将一个电影评论分类为“正”(pos),但实际上它应该是“负”(neg),这对于“正”标签来说是一个假阳性,对于“负”标签来说是一个假阴性。如果分类器正确地将其分类为“负”,那么对于“负”标签来说就是一个真阳性,对于“正”标签来说就是一个真阴性。
精度是指缺乏假阳性的程度,召回率是指缺乏假阴性的程度。这两个指标通常是相互竞争的:分类器的精度越高,召回率越低,反之亦然。
2.2 计算精度和召回率
我们可以使用以下代码计算之前训练的NaiveBayesClassifier类的精度和召回率:
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)
print(nb_precisions['pos'])
print(nb_precisions['neg'])
print(nb_recalls['pos'])
print(nb_recalls['neg'])
通过这些结果,我们可以分析分类器的性能。例如,NaiveBayesClassifier类可以正确识别大多数“正”特征集(高召回率),但也会将许多“负”特征集分类为“正”(低精度)。
2.3 计算原理
为了计算精度和召回率,我们需要为每个标签构建两个集合:
- 参考集(Reference Set):包含所有正确的值。
- 测试集(Test Set):包含分类器猜测的值。
精度的计算公式为:参考集和测试集的交集大小除以测试集的大小,即 float(len(reference.intersection(test))) / len(test) 。
召回率的计算公式为:参考集和测试集的交集大小除以参考集的大小,即 float(len(reference.intersection(test))) / len(reference) 。
2.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)的标签偏差要小得多,这是因为它根据自己的内部模型对特征进行加权。
2.5 F - 测量
F - 测量被定义为精度和召回率的加权调和平均值。如果 p 是精度, r 是召回率,公式为:
[
\frac{1}{\frac{\alpha}{p}+\frac{1 - \alpha}{r}}
]
其中, alpha 是一个加权常数,默认值为0.5。你可以使用 nltk.metrics.f_measure() 来计算F - 测量。它通常用于代替准确性来评估分类器,因为如果精度或召回率非常低,F - 测量会反映出来,但准确性可能不会。
3. 计算高信息词
3.1 高信息词和低信息词的概念
高信息词是指强烈偏向于单个分类标签的词。当我们在NaiveBayesClassifier类和MaxentClassifier类上调用 show_most_informative_features() 方法时,就可以看到这些词。令人惊讶的是,这两个分类器的顶级词是不同的,这是由于每个分类器计算每个特征重要性的方式不同。
低信息词是指所有标签中都常见的词。虽然这可能违反直觉,但从训练数据中消除这些词实际上可以提高分类器的准确性、精度和召回率。这是因为只使用高信息词可以减少分类器内部模型的噪声和混淆。
3.2 计算高信息词的步骤
我们可以使用以下代码计算电影评论语料库中的高信息词:
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 是该标签下出现的单词列表。它返回一个高信息词的集合。
3.3 使用高信息词进行特征过滤
我们可以使用 bag_of_words_in_set() 函数过滤掉所有低信息词:
def bag_of_words_in_set(words, goodwords):
return bag_of_words(set(words) & set(goodwords))
然后,我们可以使用新的特征检测器来获取新的训练和测试特征集:
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)
3.4 不同分类器使用高信息词的效果
我们对不同的分类器使用高信息词特征集进行了评估,结果如下:
| 分类器 | 准确性 | 精度(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 |
从这些结果可以看出,并非所有算法都能从高信息词过滤中受益,在某些情况下,准确性可能会降低。
3.5 高信息词计算流程
graph TD;
A[输入带标签的单词列表] --> B[计算词频和条件词频];
B --> C[为每个单词计算得分];
C --> D[过滤得分低于阈值的单词];
D --> E[返回高信息词集合];
4. 组合分类器进行投票
4.1 组合分类器的原理
提高分类性能的一种方法是组合分类器。最简单的组合多个分类器的方法是使用投票,选择获得最多投票的标签。为了避免平局,最好使用奇数个分类器,并且每个分类器应该使用不同的算法,因为多种算法的组合可以弥补单个算法的偏差。但是,将一个性能较差的分类器与性能较好的分类器组合通常不是一个好主意,因为一个分类器的较差性能可能会降低整体准确性。
4.2 准备工作
我们将使用一个NaiveBayesClassifier类、一个DecisionTreeClassifier类和一个MaxentClassifier类,这些分类器都在电影评论语料库的最高信息词上进行了训练。
4.3 实现投票分类器
我们可以使用以下代码实现一个MaxVoteClassifier类:
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()
创建这个分类器时,你需要传入一个要组合的分类器列表。创建后,它的工作方式与其他分类器相同。
4.4 评估投票分类器
from classification import MaxVoteClassifier
mv_classifier = MaxVoteClassifier(nb_classifier, dt_classifier, me_classifier, sk_classifier)
print(mv_classifier.labels())
print(accuracy(mv_classifier, test_feats))
mv_precisions, mv_recalls = precision_recall(mv_classifier, test_feats)
print(mv_precisions['pos'])
print(mv_precisions['neg'])
print(mv_recalls['pos'])
print(mv_recalls['neg'])
评估结果表明,这个投票分类器的性能与最好的sklearn分类器以及使用高信息特征的MaxentClassifier和NaiveBayesClassifier类相当。
4.5 投票分类器工作流程
graph TD;
A[输入特征集] --> B[每个分类器进行分类];
B --> C[记录每个标签的投票数];
C --> D[返回获得最多投票的标签];
通过以上方法,我们可以更全面地评估分类器的性能,并使用不同的技术来提高分类的准确性。
5. 不同分类器性能总结与分析
5.1 综合性能对比
为了更直观地比较不同分类器在各种指标下的表现,我们将之前的结果汇总如下:
| 分类器 | 准确性 | 精度(pos) | 精度(neg) | 召回率(pos) | 召回率(neg) |
|---|---|---|---|---|---|
| NaiveBayesClassifier(原始) | - | 0.6413612565445026 | 0.9576271186440678 | 0.98 | 0.452 |
| NaiveBayesClassifier(高信息词) | 0.91 | 0.8988326848249028 | 0.9218106995884774 | 0.924 | 0.896 |
| MaxentClassifier(原始) | - | 0.6456692913385826 | 0.9663865546218487 | 0.984 | 0.46 |
| MaxentClassifier(高信息词) | 0.912 | 0.8992248062015504 | 0.9256198347107438 | 0.928 | 0.896 |
| DecisionTreeClassifier(高信息词) | 0.68600000000000005 | 0.6741573033707865 | 0.69957081545064381 | 0.71999999999999997 | 0.65200000000000002 |
| SklearnClassifier(NuSVC)(原始) | - | 0.9063829787234042 | 0.8603773584905661 | 0.852 | 0.912 |
| SklearnClassifier(LinearSVC)(高信息词) | 0.86 | 0.871900826446281 | 0.8488372093023255 | 0.844 | 0.876 |
| MaxVoteClassifier | 0.894 | 0.9156118143459916 | 0.8745247148288974 | 0.868 | 0.92 |
从这个表格中我们可以看出:
- 高信息词的影响 :对于NaiveBayesClassifier和MaxentClassifier,使用高信息词后,准确性、精度和召回率都有了显著的提升,说明过滤低信息词有助于减少噪声,提高分类性能。
- 不同算法的特性 :SklearnClassifier(NuSVC)在原始状态下就表现出较低的标签偏差,这得益于其内部的特征加权模型。而DecisionTreeClassifier在使用高信息词后,性能提升不明显,可能是因为它本身已经在一定程度上对高信息特征进行了优化,但增加树的深度可能会导致过拟合和训练时间过长的问题。
- 组合分类器的效果 :MaxVoteClassifier的性能与单个表现较好的分类器相当,说明通过投票组合多个分类器可以在一定程度上弥补单个分类器的不足,提高整体的稳定性和准确性。
5.2 性能影响因素分析
不同分类器的性能受到多种因素的影响,主要包括以下几个方面:
- 算法原理 :不同的分类算法基于不同的数学模型和假设,例如NaiveBayesClassifier基于贝叶斯定理,假设特征之间相互独立;而MaxentClassifier基于最大熵原理,试图在满足已知约束的情况下最大化熵。这些不同的原理决定了它们对数据的处理方式和适应能力。
- 特征选择 :使用高信息词作为特征可以减少噪声和混淆,提高分类器的性能。但不同的分类器对特征的敏感度不同,一些算法如支持向量机和逻辑回归能够自动学习特征的权重,对特征的预处理要求相对较低;而NaiveBayesClassifier等算法则更依赖于特征的质量。
- 训练数据 :训练数据的质量和数量对分类器的性能有重要影响。如果训练数据中存在噪声或偏差,可能会导致分类器的过拟合或欠拟合。此外,数据的分布也会影响分类器的性能,例如如果某个标签的数据量过少,分类器可能无法很好地学习该标签的特征。
6. 实际应用中的建议
6.1 分类器选择
在实际应用中,选择合适的分类器需要根据具体的任务和数据特点来决定。以下是一些建议:
- 数据量较小 :如果数据量较小,NaiveBayesClassifier是一个不错的选择,因为它的训练速度快,对数据的要求相对较低。同时,可以尝试使用高信息词来提高其性能。
- 需要处理复杂特征关系 :MaxentClassifier能够处理特征之间的复杂关系,适用于需要考虑多个特征相互作用的场景。
- 对特征加权有需求 :SklearnClassifier(如NuSVC和LinearSVC)适合处理需要对特征进行加权的任务,它们能够自动学习特征的重要性,减少标签偏差。
- 需要提高稳定性 :当单个分类器的性能不稳定时,可以考虑使用组合分类器,如MaxVoteClassifier,通过投票的方式来提高分类的准确性和稳定性。
6.2 特征处理
在特征处理方面,我们可以遵循以下步骤:
- 计算高信息词 :使用
high_information_words()函数计算高信息词,过滤掉低信息词,减少噪声和混淆。 - 特征选择和优化 :根据不同的分类器和任务需求,选择合适的特征。可以尝试使用不同的特征提取方法和特征选择算法,如卡方检验、信息增益等,来进一步优化特征。
- 特征工程 :除了使用高信息词,还可以进行其他特征工程操作,如词干提取、停用词去除、词性标注等,以提高特征的质量。
6.3 性能评估
在评估分类器的性能时,不能仅仅依赖于准确性,还需要考虑精度、召回率和F - 测量等指标。具体步骤如下:
- 计算精度和召回率 :使用
precision_recall()函数计算分类器的精度和召回率,了解分类器在不同标签上的表现。 - 计算F - 测量 :使用
nltk.metrics.f_measure()计算F - 测量,综合考虑精度和召回率,评估分类器的整体性能。 - 交叉验证 :使用交叉验证的方法,将数据分成多个子集,多次训练和测试分类器,以提高评估结果的可靠性。
7. 总结
通过对不同分类器的准确性、精度、召回率等指标的评估,以及对高信息词和组合分类器的应用,我们可以更全面地了解分类器的性能,并采取相应的措施来提高分类的准确性。在实际应用中,需要根据具体的任务和数据特点,选择合适的分类器和特征处理方法,同时综合使用多种评估指标来评估分类器的性能。
以下是整个文本分类流程的总结流程图:
graph LR;
A[数据准备] --> B[特征提取];
B --> C[高信息词计算];
C --> D[特征过滤];
D --> E[分类器训练];
E --> F[性能评估];
F --> G{是否满足要求};
G -- 是 --> H[应用分类器];
G -- 否 --> I[调整参数或更换分类器];
I --> E;
在这个流程中,我们从数据准备开始,经过特征提取、高信息词计算和特征过滤等步骤,训练分类器并进行性能评估。如果评估结果不满足要求,可以调整参数或更换分类器,重新进行训练和评估,直到达到满意的性能为止。通过这样的循环优化,我们可以不断提高分类器的性能,满足实际应用的需求。
超级会员免费看

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



