关于分类文本,有三个问题

  1. 怎么识别出文本中用于明显分类的特征
  2. 怎么构建自动分类文本的模型
  3. 相关的语言知识

按照这个思路,博主进行了艰苦学习(手动捂脸。。)


一、监督式分类:建立在训练语料基础上的分类

训练过程中,特征提取器将输入转化为特征集,并且记录对应的正确分类。生成模型。预测过程中,未见过的输入被转换特征集,通过模型产生预测标签。

特征提取器和朴素贝叶斯分类器

特征提取器返回字典,这个字典被称为特征集。然后利用

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学习笔记(六):利用机器学习进行文本分类的更多相关文章

  1. 机器学习实战(Machine Learning in Action)学习笔记————09.利用PCA简化数据

    机器学习实战(Machine Learning in Action)学习笔记————09.利用PCA简化数据 关键字:PCA.主成分分析.降维作者:米仓山下时间:2018-11-15机器学习实战(Ma ...

  2. java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)

    java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...

  3. 学习笔记:利用GDI+生成简单的验证码图片

    学习笔记:利用GDI+生成简单的验证码图片 /// <summary> /// 单击图片时切换图片 /// </summary> /// <param name=&quo ...

  4. Learning ROS for Robotics Programming Second Edition学习笔记(六) indigo xtion pro live

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...

  5. Typescript 学习笔记六:接口

    中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...

  6. python3.4学习笔记(六) 常用快捷键使用技巧,持续更新

    python3.4学习笔记(六) 常用快捷键使用技巧,持续更新 安装IDLE后鼠标右键点击*.py 文件,可以看到Edit with IDLE 选择这个可以直接打开编辑器.IDLE默认不能显示行号,使 ...

  7. Spring MVC 学习笔记2 - 利用Spring Tool Suite创建一个web 项目

    Spring MVC 学习笔记2 - 利用Spring Tool Suite创建一个web 项目 Spring Tool Suite 是一个带有全套的Spring相关支持功能的Eclipse插件包. ...

  8. Go语言学习笔记六: 循环语句

    Go语言学习笔记六: 循环语句 今天学了一个格式化代码的命令:gofmt -w chapter6.go for循环 for循环有3种形式: for init; condition; increment ...

  9. 【opencv学习笔记六】图像的ROI区域选择与复制

    图像的数据量还是比较大的,对整张图片进行处理会影响我们的处理效率,因此常常只对图像中我们需要的部分进行处理,也就是感兴趣区域ROI.今天我们来看一下如何设置图像的感兴趣区域ROI.以及对ROI区域图像 ...

随机推荐

  1. linux ifconfig命令配置ip地址

    Linux下网卡命名规律:eth0,eth1. 第一块以太网卡.第二块. lo为环回接口,它的IP地址固定为127.0.0.1.掩码8位. 它代表你的机器本身.   ifconfig [Interfa ...

  2. P3202 [HNOI2009]通往城堡之路 神仙题

    这个题不是坑人吗...写个tarjan标签,然后拿这么个神仙题来搞...代码有点看不懂,有兴趣的可以去洛谷题解区看看,懒得想了. 题干: 题目描述 听说公主被关押在城堡里,彭大侠下定决心:不管一路上有 ...

  3. codevs2503失恋28天......(背包dp)

    503 失恋28天-缝补礼物  时间限制: 1 s  空间限制: 32000 KB  题目等级 : 黄金 Gold   题目描述 Description 话说上回他给女孩送了n件礼物,由于是廉价的所以 ...

  4. Akka源码分析-Remote-ActorSystem

    前面的文章都是基于local模式分析的,现在我们简要分析一下在remote模式下,ActorSystem的创建过程. final val ProviderClass: String = setup.g ...

  5. Linux下MySql数据的导入导出

    1,每天4点备份mysql数据: 2,为节省空间,删除超过3个月的所有备份数据: 3,删除超过7天的备份数据,保留3个月里的 10号 20号 30号的备份数据: mysqldump -u用戶名 -p密 ...

  6. BZOJ 3456 NTT图的计数 容斥

    思路: RT 懒得写了 //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm&g ...

  7. django 菜单权限

    一.什么是权限 能做哪些事情,不能做哪些事情,可以做的权限 二.设计权限 思路: web应用中,所谓的权限,其实就是一个用户能够访问的url,通过对用户访问的url进行控制,从而实现对用户权限的控制. ...

  8. hbuilder中的 http://www.w3.org/TR/html4/frameset.dtd

    <!-- This is the HTML 4.01 Frameset DTD, which should be used for documents with frames. This DTD ...

  9. Linux下查看CPU和内存(很详细)

    在系统维护的过程中,随时可能有需要查看 CPU 使用率,并根据相应信息分析系统状况的需要.在 CentOS 中,可以通过 top 命令来查看 CPU 使用状况.运行 top 命令后,CPU 使用状态会 ...

  10. 【转】Linux下使用locale命令设置语言环境

    转自:http://www.cnblogs.com/dolphi/p/3622570.html locale命令设置语言环境 在Linux中通过locale来设置程序运行的不同语言环境,locale由 ...