文本分类(Document Classification / Document Categorization)
▶ 分类方法1——基于规则(Hand-coded)
- 精度高
- 开销大
▶ 分类方法2——机器学习(Machine learning)
是一种计算机算法,该算法通过对数据做自动分析来获得规律,并利用这些规律对未知数据进行预测。它是人工智能的一个分支。
有监督学习 | 无监督的学习 |
---|---|
训练集包括输入和由人工标注的输出 | 其训练集没有人为标注的输出 |
分类器(classifier) | 聚类(cluster) |
常用的分类器有:朴素贝叶斯、KNN、决策树、SVM、神经网络等。
朴素贝叶斯(Naïve Bayes)
▶ 朴素贝叶斯的原理
▶ 朴素贝叶斯的优缺点
- 优:朴素贝叶斯假设了数据集属性之间相互独立,因此算法的逻辑性得到极大的简化,这使得朴素贝叶斯十分稳定,即比较健壮。
- 缺:属性的独立性条件同时也是朴素贝叶斯的不足之处,毕竟在实际中,数据集的属性之间往往存在这样那样的关联,很难满足这种属性的独立性,分类效果也会因此大大降低。
▶ 朴素贝叶斯的理解
- 属性独立性是Naïve Bayes的前提也是关键
- 这种独立性也代表着:属性无权重,它们对于决策结果的影响是平等的
- 贝叶斯方法的特点是结合先验概率和后验概率,即避免了只使用先验概率的主观偏见,也避免了单独使用样本信息的过拟合现象——通过下面的简单例子,你就能理解这句话了 >_<
▶ 如何基于这些原理实现Naïve Bayes分类器?
通俗地说,就是根据已有的数据集,得到先验概率和各种属性对于各种决策的条件概率(可以理解为每种属性对每种决策的影响的大小);面对新的场景,对于每一种决策结果,进行一串连乘,推选出概率最高者为最终决策。
一个超级简单的例子
Chinese、Beijing、Tokyo等为相互独立的属性
求第五组(text5)属于那一类(c / j) ?
▶ 手写解
▶ 代码解
text1 = "Chinese Beijing Chinese" # 分类为c
text2 = "Chinese Chinese Shanghai" # 分类为c
text3 = "Chinese Macao" # 分类为c
text4 = "Tokyo Japan Chinese" # 分类为j
text5 = "Chinese Chinese Chinese Tokyo Japan" # 分类为什么?
import re
pattern = re.compile('\w+')
# 获取单词list
C = pattern.findall(text1) + pattern.findall(text2) + pattern.findall(text3)
J = pattern.findall(text4)
All = C + J
# 词频
from nltk import *
fd_c = FreqDist(C)
fd_j = FreqDist(J)
fd_all = FreqDist(All)
# 先验概率
pc = 3 / 4
pj = 1 / 4
def Naive_Bayes_classifier(text):
pc = 1
pj = 1
pc *= 3 / 4
pj *= 1 / 4
for each in text5.split(' '):
pc *= ((fd_c[each] + 1) / (len(C) + len(fd_all)))
pj *= ((fd_j[each] + 1) / (len(J) + len(fd_all)))
print('分类为c的后验概率正比于', pc)
print('分类为j的后验概率正比于', pj)
print('最终该text的分类为(最终决策):', 'c' if pc > pj else 'j')
Naive_Bayes_classifier(text5)
NLTK提供的朴素贝叶斯分类器
############################### 基于NLTK的朴素贝叶斯分类器实现人名分类 #############################
from nltk.corpus import names # 直接利用nltk提供的语料库
print(names.fileids()) # 这个names语料库有两个文件:['female.txt', 'male.txt']
name_sex = [(name, 'male') for name in names.words('male.txt')] + [(name, 'female') for name in names.words('female.txt')]
# 把这些带标签的名字随机化
import random
random.shuffle(name_sex)
# 获取特征———以名字的最后一个字母作为特征
def get_features(word):
return {'last_name': word[-1]}
# 生成特征集合
# tip:格式为[({描述:属性特征}, 类别), ({描述:特征}, 类别), ({描述:属性特征}, 类别)...]
feature_set = [(get_features(name), sex) for (name, sex) in name_sex]
# 获得训练集和测试集
train_set = feature_set[500:]
test_set = feature_set[:500]
# 训练分类器
import nltk
classifier = nltk.NaiveBayesClassifier.train(test_set)
# 输入名字,使用分类器实现分类(实际上是预测)
name = input('>_< 请输入名字: ')
print('>_< 我猜测ta的性别是: ', classifier.classify(get_features(name)))
评估:
print(nltk.classify.accuracy(classifier, test_set)) # 0.746
上面在获取特征时(get_features)获取的是“名字的最后一个字母”,所以0.746
这个评估结果完全在预料之中
如果将整个名字作为特征:def get_features(word): return {'whole_name': word}
评估结果可达到0.998
检查分类器的有效特征
classifier.show_most_informative_features(5)