NLTK学习笔记(六):利用机器学习进行文本分类
关于分类文本,有三个问题
- 怎么识别出文本中用于明显分类的特征
- 怎么构建自动分类文本的模型
- 相关的语言知识
按照这个思路,博主进行了艰苦学习(手动捂脸。。)
一、监督式分类:建立在训练语料基础上的分类
训练过程中,特征提取器将输入转化为特征集,并且记录对应的正确分类。生成模型。预测过程中,未见过的输入被转换特征集,通过模型产生预测标签。
特征提取器和朴素贝叶斯分类器
特征提取器返回字典,这个字典被称为特征集。然后利用
nltk自带的朴素贝叶斯分类器NaiveBayesClassifier生成分类器。并且可以用nltk.classify.accuracy(分类器,测试集)测试准确度。
import nltk
from nltk.corpus import names
import random
def gender_features(word): #特征提取器
return {'last_letter':word[-1]} #特征集就是最后一个字母
names = [(name,'male') for name in names.words('male.txt')]+[(name,'female') for name in names.words('female.txt')]
random.shuffle(names)#将序列打乱
features = [(gender_features(n),g) for (n,g) in names]#返回对应的特征和标签
train,test = features[500:],features[:500] #训练集和测试集
classifier = nltk.NaiveBayesClassifier.train(train) #生成分类器
print('Neo is a',classifier.classify(gender_features('Neo')))#分类
print(nltk.classify.accuracy(classifier,test)) #测试准确度
classifier.show_most_informative_features(5)#得到似然比,检测对于哪些特征有用
当然,当我们训练大的语料库的时候,链表会占用很大内存。这时候nltk提供了:
apply_features,会生成链表,但是不会在内存中存储所有对象。
from nltk.classify import apply_features
train_set = apply_features(gender_features,names[500:])
test_set = apply_features(gender_features,names[:500])
过拟合:当特征过多
当特征过多的时候(特征集的键值过多),会对一般化的新例子不起作用,称为过拟合。如果抉择特征集的大小,需要不停的测试,找到最吻合的特征集。
错误分析
为了使特征提取器准确度更高,一般将源数据分为两大部分,三小部分:
- 开发集:
- 训练集:负责开发
- 开发测试集:负责错误分析
- 测试集:负责最终评估
下面是查找报错信息的案例:
import nltk
from nltk.corpus import names
import random
def gender_features(word): #特征提取器
return {'last_letter':word[-1]} #特征集就是最后一个字母
names = [(name,'male') for name in names.words('male.txt')]+[(name,'female') for name in names.words('female.txt')]
train_names = names[1500:]
devtest_names = names[500:1500]
test_names = names[:500]
train_set = [(gender_features(n),g) for (n,g) in train_names]
devtest_set = [(gender_features(n),g) for (n,g) in devtest_names]
test_set = [(gender_features(n),g) for (n,g) in test_names]
classifier = nltk.NaiveBayesClassifier.train(train_set)
print(nltk.classify.accuracy(classifier,devtest_set))
######################记录报错的案例###############################
errors = []
for (name,tag) in devtest_names:
guess = classifier.classify(gender_features(name))
if guess!=tag:
errors.append((tag,guess,name))
##################################################################
我们发现准确度低,因为倒数第二个字母也很有关联。所以我们可以改进特征提取器:
def gender_features(word): #特征提取器
return {'last_letter':word[-1],'last__letter':word[-2]} #特征集就是最后一个字母和倒数第二个字母
观察结果,发现,准确度提高了12%。重复这个过程,使得特征提取器更加完善。
二、实例:文本分类和词性标注
文本分类
这里的分类标签选成词汇,通过对文本前N个词的观察,得到预测标签。
import nltk
from nltk.corpus import movie_reviews
all_words = nltk.FreqDist(w.lower() for w in movie_reviews.words())
word_features = all_words.most_common(2) #前两千个最常出现的单词
def document_features(document):
document_words = set(document)
features = {}
for (word,freq) in word_features:
features['contains(%s)'%word] = (word in document_words) #参数文档中是否包含word:True/False
return features
documents = [(list(movie_reviews.words(fileid)),category) for category in movie_reviews.categories() for fileid in movie_reviews.fileids(category)]
random.shuffle(documents)
features = [(document_features(d),c)for (d,c) in documents]
train_set,test_set = features[100:],features[:100]
classifier = nltk.NaiveBayesClassifier.train(train_set)
print(nltk.classify.accuracy(classifier,test_set))
词性标注:“决策树”分类器
这里的分类器是决策树分类器:
DecisionTreeClassifier。可以通过classifier.pseudocode(depth = ?)这查询深度为depth的树,并且打印出来。顺便表示,我再走下面的程序的时候,电脑炸了。建议在集群上运行。
from nltk.corpus import brown
import nltk
suffix_fdist = nltk.FreqDist()
for word in brown.words():
word = word.lower()
#suffix_fdist.inc(word[-1:]) python2
suffix_fdist[word[-1:]] += 1 #python3
suffix_fdist[word[-2:]] += 1
suffix_fdist[word[-3:]] += 1
common_suffixes = suffix_fdist.most_common(100) #获得常见特征链表
#定义特征提取器:
def pos_features(word):
features = {}
for (suffix,times) in common_suffixes:
features['endswith(%s)' % suffix] = word.lower().endswith(suffix)
return features
tagged_words = brown.tagged_words(categories='news')
featuresets = [(pos_features(n),g)for (n,g) in tagged_words]
size = int(len(featuresets)*0.1)
train_set , test_set= featuresets[size:], featuresets[:size]
classifier = nltk.DecisionTreeClassifier.train(train_set) #“决策树分类器”
print(nltk.classify.accuracy(classifier,test_set))
三、更近一步的连续分类或贪婪序列分类:在朴素贝叶斯和“决策树”之后
这种分类模型是为了获取相关分类之间的依赖关系。为第一个输入找到最佳标签,然后再次基础上找到对应的下一个输入的最佳标签。不断重复,以至所有输入都被贴上标签。所以,我们需要提供一个参数history,用来扩展特征。
事实证明,我的电脑又炸了。
利用联合分类器模型进行词性标注:
import nltk
from nltk.corpus import brown
#带有历史的特征提取器
def pos_features(sentence,i,history):
features = {'suffix(1)':sentence[i][-1:],\
'suffix(2)':sentence[i][-2:],\
'suffix(3)':sentence[i][-3:]}
if i==0:#当它在分界线的时候,没有前置word 和 word-tag
features['prev-word'] = '<START>'
features['prev-tag'] = '<START>'
else:#记录前面的history
features['prev-word'] = sentence[i-1]
features['prev-tag'] = history[i-1]
return features
'''
###########流程式###############
tagged_sents = brown.tagged_sents(categories="news")
size = int(len(tagged_sents)*0.1)
train_sents,test_sents = tagged_sents[size:],tagged_sents[:size]
train_set = []
for tagged_sent in train_sents:
untagged_set = nltk.tag.untag(tagged_sent)
history = []
for i,(word,tag) in enumerate(tagged_sent):
featureset = pos_features(untagged_set,i,history)
history.append(tag)
train_set.append((featureset,tag))
classifier = nltk.NaiveBayesClassifier.train(train_set)
'''
#########类思想重写##################
class ConsecutivePosTagger(nltk.TaggerI): #这里定义新的选择器类,继承nltk.TaggerI
def __init__(self,train_sents):
train_set = []
for tagged_sent in train_sents:
untagged_set = nltk.tag.untag(tagged_sent) #去标签化
history = []
for i,(word,tag) in enumerate(tagged_sent):
featureset = pos_features(untagged_set,i,history)
history.append(tag) #将tag添加进去
train_set.append((featureset,tag)) #拿到了训练集
self.classifier = nltk.NaiveBayesClassifier.train(train_set) #创建训练模型
def tag(self,sentence): #必须定义tag方法
history = []
for i,word in enumerate(sentence):
featureset = pos_features(sentence,i,history)
tag = self.classifier.classify(featureset)
history.append(tag)
return zip(sentence,history)
tagged_sents = brown.tagged_sents(categories="news")
size = int(len(tagged_sents)*0.1)
train_sents,test_sents = tagged_sents[size:],tagged_sents[:size]
#print(train_sents)
tagger = ConsecutivePosTagger(train_sents)
print(tagger.evaluate(test_sents))
四、评估
之前我们选择测试集和开发集,都是在一个原有集合下。这样,示例相似程度很大,不利于推广到其他数据集。而评估最简单的度量就是准确度,即:
accuracy()函数。除了这个,精确度、召回率和F-度量值也确实影响了准确度。
- 精确度:发现项目中多少是相关的。TP/(TP+FP)
- 召回率:表示相关项目发现了多少。TP(TP+FN)
- F-度量值:精确度和召回率的调和平均数。
其中,T:true;P:Positive;F:false;N:negative。组合即可。例如TP:真阳性(正确识别为相关的),TN:真阴性(相关项目中错误识别为不想关的)
五、三种分类器的总结
之前我们发现。同样的特征集,朴素贝叶斯分类器就可以轻松跑完,但是决策树分类器不行。除了过拟合的因素外,还是因为树结构强迫特征按照特定的顺序检查,即便他是重复的,而在回溯的过程中,又有重复运算,导致时间和空间的双重浪费。
朴素贝叶斯分类器允许所有恩正“并行”起作用,从计算每个标签的先验概率开始。并且建立朴素贝叶斯的时候采用了平滑技术(在给定的贝叶斯模型上)。
最后的最大熵分类器,使用搜索技术找出一组能最大限度的提高分类器性能的参数。由于他会用迭代优化技术选择参数,花费时间很长。
六、后记
努力地看书了,然而还是没有看懂。感觉是因为相应的数学知识和算法知识没到位。以后积累充足会重看。
当然,对于现在用的层面来说,较深入的了解原理,基本可以解决大多数问题。但是要是做到算法优化,还是要自己去调参,或者改进算法。
由于博主水平有限,希望各路大牛不li赐教。
欢迎进一步交流本博文相关内容:
博客园地址 : http://www.cnblogs.com/AsuraDong/
CSDN地址 : http://blog.csdn.net/asuradong
也可以致信进行交流 : xiaochiyijiu@163.com
欢迎转载 , 但请指明出处 : )
NLTK学习笔记(六):利用机器学习进行文本分类的更多相关文章
- 机器学习实战(Machine Learning in Action)学习笔记————09.利用PCA简化数据
机器学习实战(Machine Learning in Action)学习笔记————09.利用PCA简化数据 关键字:PCA.主成分分析.降维作者:米仓山下时间:2018-11-15机器学习实战(Ma ...
- java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)
java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...
- 学习笔记:利用GDI+生成简单的验证码图片
学习笔记:利用GDI+生成简单的验证码图片 /// <summary> /// 单击图片时切换图片 /// </summary> /// <param name=&quo ...
- Learning ROS for Robotics Programming Second Edition学习笔记(六) indigo xtion pro live
中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...
- Typescript 学习笔记六:接口
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- python3.4学习笔记(六) 常用快捷键使用技巧,持续更新
python3.4学习笔记(六) 常用快捷键使用技巧,持续更新 安装IDLE后鼠标右键点击*.py 文件,可以看到Edit with IDLE 选择这个可以直接打开编辑器.IDLE默认不能显示行号,使 ...
- Spring MVC 学习笔记2 - 利用Spring Tool Suite创建一个web 项目
Spring MVC 学习笔记2 - 利用Spring Tool Suite创建一个web 项目 Spring Tool Suite 是一个带有全套的Spring相关支持功能的Eclipse插件包. ...
- Go语言学习笔记六: 循环语句
Go语言学习笔记六: 循环语句 今天学了一个格式化代码的命令:gofmt -w chapter6.go for循环 for循环有3种形式: for init; condition; increment ...
- 【opencv学习笔记六】图像的ROI区域选择与复制
图像的数据量还是比较大的,对整张图片进行处理会影响我们的处理效率,因此常常只对图像中我们需要的部分进行处理,也就是感兴趣区域ROI.今天我们来看一下如何设置图像的感兴趣区域ROI.以及对ROI区域图像 ...
随机推荐
- QT Creater环境搭建
需要的软件包: 1.qt-win-opensource-4.8.5-mingw.exe //Qt库 2.MinGW-gcc440_1.zip //QT编译器 3.qt-creator-opensour ...
- Python机器学习算法 — K-Means聚类
K-Means简介 步,直到每个簇的中心基本不再变化: 6)将结果输出. K-Means的说明 如图所示,数据样本用圆点表示,每个簇的中心点用叉叉表示: (a)刚开始时是原始数据,杂乱无章 ...
- php验证手机号是否合法
用正则匹配手机号码的时候, 我们先分析一下手机号码的规律: 1. 手机号通常是11位的 2. 经常是1开头 3. 第二个数字通常是34578这几个数字, 2014.5.5日170号段的手机号开卖所以这 ...
- 吝啬的国度 ---用vector 来构图
根据题目可以看出来 有n 个城市 只有 n-1 条路线 那么 就可以确定这个图中 不存在 圆 所以从一个点到另一个点 只有一条唯一的路 所以从一个节点到另一个节点 那么 这个节点只有一个唯 ...
- $luogu2375[NOI2014]$
\(problem\) 其中,\(next[i],next[next[i]],next[next[next[i]]]......\)都是这个前缀串i的公共前后缀,而且只有它们是公共前后缀 那么,我们其 ...
- mongoDB的基本用法
一.MongoDB初识 什么是MongoDB MongoDB是一个基于分布式文件存储的数据库.由c++语言编写.旨在为web应用提供可扩展的高性能数据存储解决方案. MongoDB是一个介于关系数据库 ...
- 题解报告:hdu 1846 Brave Game(巴什博弈)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1846 Problem Description 十年前读大学的时候,中国每年都要从国外引进一些电影大片, ...
- python中的深拷贝和浅拷贝(面试题二)
一.浅拷贝 定义:浅拷贝只是对另外一个变量的内存地址的拷贝,这两个变量指向同一个内存地址的变量值. 浅拷贝的特点: 公用一个值: 这两个变量的内存地址一样: 对其中一个变量的值改变,另外一个变量的值也 ...
- Appium Appium 链接夜神模拟器
在此之前,已经安装Appium,参考第一部分在 Windows7 搭建 Appium (一) https://testerhome.com/topics/8004 第一步安装Android开发环境 下 ...
- 【转】Linux之printf命令
转自:http://blog.chinaunix.net/uid-9525959-id-2001528.html printf FORMAT [ARGUMENT]... printf OPTION [ ...