📅  最后修改于: 2020-10-14 09:29:37             🧑  作者: Mango
顾名思义,文本分类是对文本或文档进行分类的方法。但是这里出现了一个问题,为什么我们需要使用文本分类器?一旦检查了文档或一段文本中的单词用法,分类器将能够决定应为其分配什么类别标签。
顾名思义,二进制分类器将在两个标签之间决定。例如,正面或负面。在这种情况下,文本或文档可以是一个标签,也可以是另一个标签,但不能同时是两者。
与二进制分类器相反,多标签分类器可以将一个或多个标签分配给一段文本或文档。
特征名称到特征值的键值映射称为特征集。标记的特征集或训练数据对于分类训练非常重要,以便以后可以对未标记的特征集进行分类。
Labeled Feature Set | Unlabeled Feature Set |
---|---|
It is a tuple that look like (feat, label). | It is a feat itself. |
It is an instance with a known class label. | Without associated label, we can call it an instance. |
Used for training a classification algorithm. | Once trained, classification algorithm can classify an unlabeled feature set. |
顾名思义,文本特征提取是将单词列表转换为分类器可用的特征集的过程。我们必须将文本转换为“ dict”样式功能集,因为自然语言工具包(NLTK)期望使用“ dict”样式功能集。
BoW是NLP中最简单的模型之一,用于从文本或文档中提取特征,以便可以将其用于建模(例如ML算法)中。它基本上从实例的所有单词构造单词存在功能集。该方法背后的概念是,它不关心单词出现的次数或单词的顺序,仅关心天气单词在单词列表中是否存在。
对于此示例,我们将定义一个名为bow()的函数-
def bow(words):
return dict([(word, True) for word in words])
现在,让我们在单词上调用bow()函数。我们将此功能保存在名为bagwords.py的文件中。
from bagwords import bow
bow(['we', 'are', 'using', 'tutorialspoint'])
{'we': True, 'are': True, 'using': True, 'tutorialspoint': True}
在前面的部分中,我们学习了如何从文本中提取特征。因此,现在我们可以训练分类器了。第一个也是最简单的分类器是NaiveBayesClassifier类。
为了预测给定特征集属于特定标签的概率,它使用贝叶斯定理。贝叶斯定理的公式如下。
$$ P(A | B)= \ frac {P(B | A)P(A)} {P(B)} $$
这里,
P(A | B) -也称为后验概率,即在发生第二事件即B的情况下发生第一事件即A的概率。
P(B | A) -这是第二个事件(即B)在第一个事件(即A)发生之后发生的概率。
P(A),P(B) -也称为先验概率,即发生第一事件(即A)或第二事件(即B)的概率。
为了训练朴素贝叶斯分类器,我们将使用NLTK的movie_reviews语料库。该语料库有两类文本,即: pos和neg 。这些类别使经过分类训练的分类器成为二进制分类器。语料库中的每个文件都由两个组成,一个是正面电影评论,另一个是负面电影评论。在我们的示例中,我们将使用每个文件作为单个实例来训练和测试分类器。
对于训练分类器,我们需要一个带标签的功能集列表,形式为[( featuresset,label )]。这里的功能集的变量是一个字典和标签是用于FEATURESET的已知类别的标签。我们要创建一个名为label_corpus()函数将采取文集命名movie_reviews,也是一个函数叫feature_detector,默认为文字包。它将构造并返回形式为{label:[featureset]}的映射。之后,我们将使用此映射来创建带有标签的训练实例和测试实例的列表。
进口馆藏
def label_corpus(corp, feature_detector=bow):
label_feats = collections.defaultdict(list)
for label in corp.categories():
for fileid in corp.fileids(categories=[label]):
feats = feature_detector(corp.words(fileids=[fileid]))
label_feats[label].append(feats)
return label_feats
借助以上函数,我们将获得一个映射{label:fetaureset} 。现在,我们将定义另一个名为split的函数,该函数将获取label_corpus()函数返回的映射,并将每个功能集列表拆分为带标签的训练和测试实例。
def split(lfeats, split=0.75):
train_feats = []
test_feats = []
for label, feats in lfeats.items():
cutoff = int(len(feats) * split)
train_feats.extend([(feat, label) for feat in feats[:cutoff]])
test_feats.extend([(feat, label) for feat in feats[cutoff:]])
return train_feats, test_feats
现在,让我们在语料库上使用这些功能,即movie_reviews-
from nltk.corpus import movie_reviews
from featx import label_feats_from_corpus, split_label_feats
movie_reviews.categories()
['neg', 'pos']
lfeats = label_feats_from_corpus(movie_reviews)
lfeats.keys()
dict_keys(['neg', 'pos'])
train_feats, test_feats = split_label_feats(lfeats, split = 0.75)
len(train_feats)
1500
len(test_feats)
500
我们已经看到在movie_reviews语料库中,有1000个pos文件和1000个neg文件。我们最终得到了1500个带有标签的训练实例和500个带有标签的测试实例。
现在让我们使用其train()类方法训练NaïveBayesClassifier-
from nltk.classify import NaiveBayesClassifier
NBC = NaiveBayesClassifier.train(train_feats)
NBC.labels()
['neg', 'pos']
另一个重要的分类器是决策树分类器。在这里训练它, DecisionTreeClassifier类将创建一个树结构。在此树结构中,每个节点对应于一个要素名称,而分支对应于这些要素值。沿着树枝,我们将到达树的叶子,即分类标签。
为了训练决策树分类器,我们将使用相同的训练和测试功能,即train_feats和test_feats ,这是我们从movie_reviews语料库创建的变量。
为了训练这个分类器,我们将调用DecisionTreeClassifier.train()类方法,如下所示:
from nltk.classify import DecisionTreeClassifier
decisiont_classifier = DecisionTreeClassifier.train(
train_feats, binary = True, entropy_cutoff = 0.8,
depth_cutoff = 5, support_cutoff = 30
)
accuracy(decisiont_classifier, test_feats)
0.725
另一个重要的分类器是MaxentClassifier ,也称为条件指数分类器或逻辑回归分类器。在这里进行训练, MaxentClassifier类将使用编码将标记的功能集转换为向量。
为了训练决策树分类器,我们将使用相同的训练和测试功能,即train_feats和test_feats ,这是我们从movie_reviews语料库创建的变量。
为了训练这个分类器,我们将调用MaxentClassifier.train()类方法,如下所示:
from nltk.classify import MaxentClassifier
maxent_classifier = MaxentClassifier
.train(train_feats,algorithm = 'gis', trace = 0, max_iter = 10, min_lldelta = 0.5)
accuracy(maxent_classifier, test_feats)
0.786
最好的机器学习(ML)库之一是Scikit-learn。它实际上包含用于各种目的的各种ML算法,但是它们都具有如下相同的适合设计模式-
在这里,我们将使用NLTK的SklearnClassifier类,而不是直接访问scikit-learn模型。此类是围绕scikit-learn模型的包装器类,以使其符合NLTK的Classifier接口。
我们将按照以下步骤训练SklearnClassifier类-
步骤1-首先,我们将像以前的食谱一样创建训练功能。
步骤2-现在,选择并导入Scikit学习算法。
步骤3-接下来,我们需要使用所选算法构造一个SklearnClassifier类。
步骤4-最后,我们将使用我们的训练功能训练SklearnClassifier类。
让我们在下面的Python配方中实现这些步骤-
from nltk.classify.scikitlearn import SklearnClassifier
from sklearn.naive_bayes import MultinomialNB
sklearn_classifier = SklearnClassifier(MultinomialNB())
sklearn_classifier.train(train_feats)
accuracy(sk_classifier, test_feats)
0.885
在训练各种分类器时,我们也测量了它们的准确性。但是除了准确性,还有许多其他指标可用于评估分类器。这些指标中的两个是精度和召回率。
在此示例中,我们将计算精度和召回我们先前训练的NaiveBayesClassifier类。为此,我们将创建一个名为metrics_PR()的函数,该函数将使用两个参数,一个是训练有素的分类器,另一个是标记的测试功能。这两个参数与我们在计算分类器的准确性时传递的参数相同-
import collections
from nltk import metrics
def metrics_PR(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 metrics_classification import metrics_PR
nb_precisions, nb_recalls = metrics_PR(nb_classifier,test_feats)
nb_precisions['pos']
0.6713532466435213
nb_precisions['neg']
0.9676271186440678
nb_recalls['pos']
0.96
nb_recalls['neg']
0.478
组合分类器是提高分类性能的最佳方法之一。投票是组合多个分类器的最佳方法之一。为了进行投票,我们需要使用奇数个分类器。在下面的Python食谱中,我们将结合三个分类器,即NaiveBayesClassifier类,DecisionTreeClassifier类和MaxentClassifier类。
为了实现这一点,我们将如下定义一个名为voting_classifiers()的函数。
import itertools
from nltk.classify import ClassifierI
from nltk.probability import FreqDist
class Voting_classifiers(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()
让我们调用此函数来组合三个分类器并找到精度-
from vote_classification import Voting_classifiers
combined_classifier = Voting_classifiers(NBC, decisiont_classifier, maxent_classifier)
combined_classifier.labels()
['neg', 'pos']
accuracy(combined_classifier, test_feats)
0.948
从上面的输出中,我们可以看到组合分类器比单个分类器具有最高的准确性。