文本分类:多标签分类器与NLTK-Trainer的使用
1. 多标签分类器的构建
在文本分类任务中,我们通常会遇到需要对文本进行多标签分类的情况。多标签分类器可以为一个文本样本分配多个标签,而不仅仅是一个。下面我们将详细介绍如何使用多个二元分类器来构建一个多标签分类器。
1.1 准备工作
我们使用路透社(Reuters)语料库进行训练和评估,该语料库包含了多标签的文本数据。首先,我们需要计算路透社语料库中的高信息词,这可以通过
featx.py
中的
reuters_high_info_words()
函数实现:
from nltk.corpus import reuters
from nltk.collocations import BigramAssocMeasures
def reuters_high_info_words(score_fn=BigramAssocMeasures.chi_sq):
labeled_words = []
for label in reuters.categories():
labeled_words.append((label, reuters.words(categories=[label])))
return high_information_words(labeled_words, score_fn=score_fn)
接下来,我们需要根据这些高信息词获取训练和测试特征集,这可以通过
featx.py
中的
reuters_train_test_feats()
函数实现:
def reuters_train_test_feats(feature_detector=bag_of_words):
train_feats = []
test_feats = []
for fileid in reuters.fileids():
if fileid.startswith('training'):
featlist = train_feats
else: # fileid.startswith('test')
featlist = test_feats
feats = feature_detector(reuters.words(fileid))
labels = reuters.categories(fileid)
featlist.append((feats, labels))
return train_feats, test_feats
我们可以使用这两个函数来获取多标签的训练和测试特征集:
from featx import reuters_high_info_words, reuters_train_test_feats
rwords = reuters_high_info_words()
featdet = lambda words: bag_of_words_in_set(words, rwords)
multi_train_feats, multi_test_feats = reuters_train_test_feats(featdet)
1.2 训练二元分类器
我们使用
classification.py
中的
train_binary_classifiers()
函数为每个标签训练一个二元分类器:
import collections
def train_binary_classifiers(trainf, labelled_feats, labelset):
pos_feats = collections.defaultdict(list)
neg_feats = collections.defaultdict(list)
classifiers = {}
for feat, labels in labelled_feats:
for label in labels:
pos_feats[label].append(feat)
for label in labelset - set(labels):
neg_feats[label].append(feat)
for label in labelset:
postrain = [(feat, label) for feat in pos_feats[label]]
negtrain = [(feat, '!%s' % label) for feat in neg_feats[label]]
classifiers[label] = trainf(postrain + negtrain)
return classifiers
为了使用这个函数,我们需要提供一个训练函数,这里我们使用
sklearn
的逻辑回归
SklearnClassifier
类:
from classification import train_binary_classifiers
from nltk.classify import SklearnClassifier
from sklearn.linear_model import LogisticRegression
trainf = lambda train_feats: SklearnClassifier(LogisticRegression()).train(train_feats)
labelset = set(reuters.categories())
classifiers = train_binary_classifiers(trainf, multi_train_feats, labelset)
1.3 构建多标签分类器
我们定义一个
MultiBinaryClassifier
类,它继承自
nltk.classify.MultiClassifierI
接口:
from nltk.classify import MultiClassifierI
class MultiBinaryClassifier(MultiClassifierI):
def __init__(self, *label_classifiers):
self._label_classifiers = dict(label_classifiers)
self._labels = sorted(self._label_classifiers.keys())
def labels(self):
return self._labels
def classify(self, feats):
lbls = set()
for label, classifier in self._label_classifiers.items():
if classifier.classify(feats) == label:
lbls.add(label)
return lbls
我们可以使用刚刚训练好的二元分类器来构建这个多标签分类器:
from classification import MultiBinaryClassifier
multi_classifier = MultiBinaryClassifier(*classifiers.items())
1.4 评估多标签分类器
我们使用
classification.py
中的
multi_metrics()
函数来评估多标签分类器,该函数会计算每个标签的精确率、召回率以及平均Masi距离:
import collections
from nltk import metrics
def multi_metrics(multi_classifier, test_feats):
mds = []
refsets = collections.defaultdict(set)
testsets = collections.defaultdict(set)
for i, (feat, labels) in enumerate(test_feats):
for label in labels:
refsets[label].add(i)
guessed = multi_classifier.classify(feat)
for label in guessed:
testsets[label].add(i)
mds.append(metrics.masi_distance(set(labels), guessed))
avg_md = sum(mds) / float(len(mds))
precisions = {}
recalls = {}
for label in multi_classifier.labels():
precisions[label] = metrics.precision(refsets[label], testsets[label])
recalls[label] = metrics.recall(refsets[label], testsets[label])
return precisions, recalls, avg_md
使用这个函数评估我们的多标签分类器:
from classification import multi_metrics
multi_precisions, multi_recalls, avg_md = multi_metrics(multi_classifier, multi_test_feats)
2. 多标签分类器的工作原理
下面是多标签分类器的工作流程:
1.
计算高信息词
:
reuters_high_info_words()
函数会为路透社语料库的每个类别构建一个
[(label, words)]
列表,然后将其传递给
high_information_words()
函数,返回路透社语料库中最具信息量的词列表。
2.
创建特征检测器
:使用
bag_of_words_in_set()
函数创建一个特征检测器函数,并将其传递给
reuters_train_test_feats()
函数,该函数会返回两个列表,一个包含所有训练文件的
[(feats, labels)]
,另一个包含所有测试文件的相同信息。
3.
训练二元分类器
:
train_binary_classifiers()
函数会为每个标签构建两个列表,一个包含正训练特征集,另一个包含负训练特征集。正特征集是那些分类为该标签的特征集,负特征集则来自其他所有标签的正特征集。然后使用给定的训练函数为每个标签训练一个二元分类器。
4.
创建多标签分类器
:使用训练好的二元分类器创建
MultiBinaryClassifier
类的实例,该类扩展了
nltk.classify.MultiClassifierI
接口,需要实现
labels()
和
classify()
两个函数。
5.
评估多标签分类器
:使用
multi_metrics()
函数评估多标签分类器,该函数会计算每个标签的精确率、召回率以及平均Masi距离。
下面是多标签分类器的继承图:
graph TD;
MultiClassifierI --> MultiBinaryClassifier;
MultiClassifierI --> labels();
MultiClassifierI --> classify();
MultiBinaryClassifier --> labels();
MultiBinaryClassifier --> classify();
3. 类不平衡问题
路透社语料库的性质会引入类不平衡问题,即某些标签的特征集很少,而其他标签的特征集很多。这会导致二元分类器在训练时偏向负标签,因为负实例远远多于正实例。解决这个问题有一些高级技术,但这里不做详细介绍。
4. 使用NLTK-Trainer训练分类器
NLTK-Trainer是一个可以从命令行训练NLTK分类器的工具。下面我们将介绍如何使用
train_classifier.py
脚本进行分类器的训练。
4.1 基本使用
train_classifier.py
脚本的唯一必需参数是语料库的名称,语料库必须有
categories()
方法。以下是在电影评论(movie_reviews)语料库上运行
train_classifier.py
的示例:
$ python train_classifier.py movie_reviews
运行结果如下:
loading movie_reviews
2 labels: ['neg', 'pos']
using bag of words feature extraction
2000 training feats, 2000 testing feats
training NaiveBayes classifier
accuracy: 0.967000
neg precision: 1.000000
neg recall: 0.934000
neg f-measure: 0.965874
pos precision: 0.938086
pos recall: 1.000000
pos f-measure: 0.968054
dumping NaiveBayesClassifier to ~/nltk_data/classifiers/movie_reviews_NaiveBayes.pickle
我们可以使用
--no-pickle
参数跳过保存分类器,使用
--fraction
参数限制训练集并评估分类器:
$ python train_classifier.py movie_reviews --no-pickle --fraction 0.75
4.2 工作原理
train_classifier.py
脚本会经过以下步骤来训练分类器:
1.
加载分类语料库
:加载指定的语料库。
2.
提取特征
:默认使用词袋(bag of words)特征提取方法。
3.
训练分类器
:默认使用朴素贝叶斯(NaiveBayes)分类器。
根据使用的参数,可能还会有其他步骤,如评估分类器和/或保存分类器。
4.3 其他参数和功能
train_classifier.py
脚本支持许多其他参数,以下是一些常见的参数和功能:
-
保存分类器
:不使用
--no-pickle
参数时,脚本会将分类器保存为
~/nltk_data/classifiers/NAME.pickle
,其中
NAME
是语料库名称和训练算法的组合。可以使用
--filename
参数指定自定义文件名。
-
使用不同的训练实例
:默认使用单个文件作为训练实例,也可以使用段落或句子作为训练实例,例如:
$ python train_classifier.py movie_reviews --no-pickle --fraction 0.75 --instances sents
-
查看最具信息量的特征
:可以使用
--show-most-informative参数查看最具信息量的特征,例如:
$ python train_classifier.py movie_reviews --no-pickle --fraction 0.75 --show-most-informative 5
-
使用不同的分类器
:可以使用
--classifier参数选择不同的分类器,例如:
$ python train_classifier.py movie_reviews --no-pickle --fraction 0.75 --classifier DecisionTree --trace 0 --entropy_cutoff 0.8 --depth_cutoff 5 --support_cutoff 30 --binary
-
使用Maxent和LogisticRegression分类器
:可以使用
--classifier参数指定Maxent和LogisticRegression分类器,例如:
$ python train_classifier.py movie_reviews --no-pickle --fraction 0.75 --classifier GIS --max_iter 10 --min_lldelta 0.5
$ python train_classifier.py movie_reviews --no-pickle --fraction 0.75 --classifier sklearn.LogisticRegression
-
使用SVM分类器
:可以使用
--classifier参数指定SVM分类器,例如:
$ python train_classifier.py movie_reviews --no-pickle --fraction 0.75 --classifier sklearn.LinearSVC
$ python train_classifier.py movie_reviews --no-pickle --fraction 0.75 --classifier sklearn.NuSVC
-
组合分类器
:可以使用
--classifier参数组合多个分类器,例如:
$ python train_classifier.py movie_reviews --no-pickle --fraction 0.75 --classifier sklearn.LogisticRegression sklearn.MultinomialNB sklearn.NuSVC
-
使用高信息词和二元组
:可以使用
--min_score和--ngrams参数使用高信息词和二元组作为特征,例如:
$ python train_classifier.py movie_reviews --no-pickle --fraction 0.75 --classifier NaiveBayes --min_score 5 --ngrams 1 2
-
交叉验证
:可以使用
--cross-fold参数进行交叉验证,例如:
$ python train_classifier.py movie_reviews --classifier sklearn.LogisticRegression --cross-fold 10
4.4 分析分类器
NLTK-Trainer还包含一个名为
analyze_classifier_coverage.py
的脚本,可以用来分析分类器对给定语料库的分类情况。以下是一个示例:
$ python analyze_classifier_coverage.py movie_reviews --classifier classifiers/movie_reviews_NaiveBayes.pickle --metrics --speed
通过以上介绍,我们可以看到如何使用多个二元分类器构建多标签分类器,以及如何使用NLTK-Trainer工具进行分类器的训练和评估。这些方法和工具可以帮助我们更好地完成文本分类任务。
文本分类:多标签分类器与NLTK-Trainer的使用
5. 不同参数和功能的详细对比
为了更直观地了解
train_classifier.py
脚本不同参数和功能的效果,下面我们通过表格的形式进行对比:
| 参数或功能 | 说明 | 示例命令 | 主要效果 |
| — | — | — | — |
|
--no-pickle
| 跳过保存分类器 |
python train_classifier.py movie_reviews --no-pickle
| 不将训练好的分类器保存到本地 |
|
--fraction
| 限制训练集大小 |
python train_classifier.py movie_reviews --no-pickle --fraction 0.75
| 按比例划分训练集和测试集 |
|
--filename
| 指定分类器保存的自定义文件名 |
python train_classifier.py movie_reviews --filename path/to/classifier.pickle
| 分类器保存到指定路径和文件名 |
|
--instances
| 使用不同的训练实例 |
python train_classifier.py movie_reviews --no-pickle --fraction 0.75 --instances sents
| 可以使用句子、段落等作为训练实例 |
|
--show-most-informative
| 查看最具信息量的特征 |
python train_classifier.py movie_reviews --no-pickle --fraction 0.75 --show-most-informative 5
| 显示指定数量的最具信息量的特征 |
|
--classifier
| 选择不同的分类器 |
python train_classifier.py movie_reviews --no-pickle --fraction 0.75 --classifier DecisionTree
| 可以使用不同的分类算法进行训练 |
|
--min_score
和
--ngrams
| 使用高信息词和二元组作为特征 |
python train_classifier.py movie_reviews --no-pickle --fraction 0.75 --classifier NaiveBayes --min_score 5 --ngrams 1 2
| 只使用满足分数要求的词和指定的n-gram作为特征 |
|
--cross-fold
| 进行交叉验证 |
python train_classifier.py movie_reviews --classifier sklearn.LogisticRegression --cross-fold 10
| 评估分类算法的稳定性 |
6. 组合分类器的效果分析
在之前的介绍中,我们提到了可以使用
train_classifier.py
脚本组合多个分类器。下面我们通过具体的例子来分析组合分类器的效果。
$ python train_classifier.py movie_reviews --no-pickle --fraction 0.75 --classifier sklearn.LogisticRegression sklearn.MultinomialNB sklearn.NuSVC
运行上述命令后,会得到组合分类器的评估结果。与单个分类器相比,组合分类器通过将多个分类器的概率相加来产生最终的概率分布,从而进行分类。这种方法可以综合多个分类器的优势,提高分类的准确性。
例如,在某些情况下,逻辑回归(LogisticRegression)可能对某些特征的分类效果较好,而多项式朴素贝叶斯(MultinomialNB)对另一些特征的分类效果较好。通过组合这两个分类器,可以在不同的特征上发挥各自的优势,从而提高整体的分类性能。
7. 高信息词和二元组的应用优势
使用高信息词和二元组作为特征可以提高分类的准确性。当我们使用
--min_score
和
--ngrams
参数时,
train_classifier.py
脚本会只选择那些信息增益高的词和指定的n-gram作为特征。
$ python train_classifier.py movie_reviews --no-pickle --fraction 0.75 --classifier NaiveBayes --min_score 5 --ngrams 1 2
这样做的好处是可以减少特征的数量,同时保留最具信息量的特征。在文本分类中,很多词可能对分类的贡献不大,甚至会引入噪声。通过选择高信息词和二元组,可以提高分类器的效率和准确性。
8. 交叉验证的重要性
交叉验证是评估分类算法稳定性的重要方法。通过
--cross-fold
参数,
train_classifier.py
脚本可以将训练语料库分成多个折叠,依次使用不同的折叠进行测试。
$ python train_classifier.py movie_reviews --classifier sklearn.LogisticRegression --cross-fold 10
交叉验证的流程如下:
graph LR;
A[将训练语料库分成10个折叠] --> B[选择一个折叠作为测试集,其余9个作为训练集];
B --> C[训练分类器并评估];
C --> D[重复步骤B和C,直到每个折叠都作为测试集使用过一次];
D --> E[计算所有折叠的评估结果的平均值和方差];
通过交叉验证,可以避免训练集的偏差对评估结果的影响,更准确地评估分类算法的性能。例如,如果只使用一次划分的训练集和测试集进行评估,可能会因为训练集和测试集的分布不均匀而得到不准确的结果。而交叉验证可以通过多次使用不同的训练集和测试集,得到更稳定和可靠的评估结果。
9. 分析分类器脚本的使用场景
analyze_classifier_coverage.py
脚本可以帮助我们分析分类器对给定语料库的分类情况。以下是使用该脚本的具体步骤:
1.
准备工作
:确保已经有训练好的分类器保存为pickle文件,并且知道语料库的名称。
2.
运行脚本
:使用以下命令运行脚本:
$ python analyze_classifier_coverage.py movie_reviews --classifier classifiers/movie_reviews_NaiveBayes.pickle --metrics --speed
- 分析结果 :脚本会输出分类器的准确率、精确率、召回率等指标,以及平均分类时间。通过这些结果,我们可以了解分类器的性能和效率。
这个脚本的使用场景包括:
-
评估分类器的性能
:在训练好分类器后,使用该脚本可以快速评估分类器在给定语料库上的性能。
-
比较不同分类器
:可以使用该脚本对不同的分类器进行评估和比较,选择性能最好的分类器。
-
优化分类器
:通过分析分类器的错误分类情况,可以找出分类器的不足之处,从而进行优化。
10. 总结与展望
通过本文的介绍,我们详细了解了如何使用多个二元分类器构建多标签分类器,以及如何使用NLTK-Trainer工具进行分类器的训练和评估。多标签分类器可以为文本样本分配多个标签,适用于很多实际的文本分类任务。NLTK-Trainer工具提供了丰富的参数和功能,可以帮助我们灵活地训练和评估分类器。
在未来的文本分类任务中,我们可以进一步探索以下方向:
-
更复杂的特征工程
:除了高信息词和二元组,还可以尝试使用其他的特征工程方法,如词嵌入、词性标注等,以提高分类的准确性。
-
更先进的分类算法
:随着机器学习和深度学习的发展,不断有新的分类算法出现。可以尝试使用这些新的算法,如深度学习中的卷积神经网络(CNN)、循环神经网络(RNN)等,来提高分类的性能。
-
多模态分类
:结合文本、图像、音频等多种模态的信息进行分类,以应对更复杂的分类任务。
通过不断地探索和实践,我们可以在文本分类领域取得更好的成果。
超级会员免费看
465

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



