热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:数据挖掘:朴素贝叶斯分类算法原理与实践

篇首语:本文由编程笔记#小编为大家整理,主要介绍了数据挖掘:朴素贝叶斯分类算法原理与实践相关的知识,希望对你有一定的参考价值。

篇首语:本文由编程笔记#小编为大家整理,主要介绍了数据挖掘:朴素贝叶斯分类算法原理与实践相关的知识,希望对你有一定的参考价值。





出处:fengfenggirl(@也爱数据挖掘) 


网址:http://www.cnblogs.com/fengfenggirl/p/classification_evaluate.html



本系列:







今天介绍一下朴素贝叶斯分类算法,讲一下基本原理,再以文本分类实践。


一个简单的例子


朴素贝叶斯算法是一个典型的统计学习方法,主要理论基础就是一个贝叶斯公式,贝叶斯公式的基本定义如下:



这个公式虽然看上去简单,但它却能总结历史,预知未来。公式的右边是总结历史,公式的左边是预知未来,如果把Y看出类别,X看出特征,P(Yk|X)就是在已知特征X的情况下求Yk类别的概率,而对P(Yk|X)的计算又全部转化到类别Yk的特征分布上来。


举个例子,大学的时候,某男生经常去图书室晚自习,发现他喜欢的那个女生也常去那个自习室,心中窃喜,于是每天买点好吃点在那个自习室蹲点等她来,可是人家女生不一定每天都来,眼看天气渐渐炎热,图书馆又不开空调,如果那个女生没有去自修室,该男生也就不去,每次男生鼓足勇气说:“嘿,你明天还来不?”,“啊,不知道,看情况”。


然后该男生每天就把她去自习室与否以及一些其他情况做一下记录,用Y表示该女生是否去自习室,即Y={去,不去},X是跟去自修室有关联的一系列条件,比如当天上了哪门主课,蹲点统计了一段时间后,该男生打算今天不再蹲点,而是先预测一下她会不会去,现在已经知道了今天上了常微分方法这么主课,于是计算P(Y=去|常微分方程)与P(Y=不去|常微分方程),看哪个概率大,


如果 P(Y=去|常微分方程) > P(Y=不去|常微分方程),那这个男生不管多热都屁颠屁颠去自习室了,否则不就去自习室受罪了。P(Y=去|常微分方程)的计算可以转为计算以前她去的情况下,那天主课是常微分的概率P(常微分方程|Y=去),注意公式右边的分母对每个类别(去/不去)都是一样的,所以计算的时候忽略掉分母,这样虽然得到的概率值已经不再是0~1之间,但是其大小还是能选择类别。


后来他发现还有一些其他条件可以挖,比如当天星期几、当天的天气,以及上一次与她在自修室的气氛,统计了一段时间后,该男子一计算,发现不好算了,因为总结历史的公式:


数据挖掘(8):朴素贝叶斯分类算法原理与实践


这里n=3,x(1)表示主课,x(2)表示天气,x(3)表示星期几,x(4)表示气氛,Y仍然是{去,不去},现在主课有8门,天气有晴、雨、阴三种、气氛有A+,A,B+,B,C五种,那么总共需要估计的参数有8*3*7*5*2=1680个,每天只能收集到一条数据,那么等凑齐1680条数据大学都毕业了,男生打呼不妙,于是做了一个独立性假设,假设这些影响她去自习室的原因是独立互不相关的,于是


数据挖掘(8):朴素贝叶斯分类算法原理与实践


有了这个独立假设后,需要估计的参数就变为,(8+3+7+5)*2 = 46个了,而且每天收集的一条数据,可以提供4个参数,这样该男生就预测越来越准了。


朴素贝叶斯分类器


讲了上面的小故事,我们来朴素贝叶斯分类器的表示形式:


数据挖掘(8):朴素贝叶斯分类算法原理与实践


当特征为为x时,计算所有类别的条件概率,选取条件概率最大的类别作为待分类的类别。由于上公式的分母对每个类别都是一样的,因此计算时可以不考虑分母,即


数据挖掘(8):朴素贝叶斯分类算法原理与实践


朴素贝叶斯的朴素体现在其对各个条件的独立性假设上,加上独立假设后,大大减少了参数假设空间。


在文本分类上的应用


文本分类的应用很多,比如垃圾邮件和垃圾短信的过滤就是一个2分类问题,新闻分类、文本情感分析等都可以看成是文本分类问题,分类问题由两步组成:训练和预测,要建立一个分类模型,至少需要有一个训练数据集。贝叶斯模型可以很自然地应用到文本分类上:现在有一篇文档d(Document),判断它属于哪个类别ck,只需要计算文档d属于哪一个类别的概率最大:


数据挖掘(8):朴素贝叶斯分类算法原理与实践


在分类问题中,我们并不是把所有的特征都用上,对一篇文档d,我们只用其中的部分特征词项(nd表示d中的总词条数目),因为很多词项对分类是没有价值的,比如一些停用词“的,是,在”在每个类别中都会出现,这个词项还会模糊分类的决策面,关于特征词的选取,我的这篇文章有介绍。用特征词项表示文档后,计算文档d的类别转化为:


数据挖掘(8):朴素贝叶斯分类算法原理与实践


注意P(Ck|d)只是正比于后面那部分公式,完整的计算还有一个分母,但我们前面讨论了,对每个类别而已分母都是一样的,于是在我们只需要计算分子就能够进行分类了。实际的计算过程中,多个概率值P(tj|ck)的连乘很容易下溢出为0,因此转化为对数计算,连乘就变成了累加:


数据挖掘(8):朴素贝叶斯分类算法原理与实践


我们只需要从训练数据集中,计算每一个类别的出现概率P(ck)和每一个类别中各个特征词项的概率P(tj|ck),而这些概率值的计算都采用最大似然估计,说到底就是统计每个词在各个类别中出现的次数和各个类别的文档的数目:


数据挖掘(8):朴素贝叶斯分类算法原理与实践

数据挖掘(8):朴素贝叶斯分类算法原理与实践



其中,Nck表示训练集中ck类文档的数目,N训练集中文档总数;Tjk表示词项tj在类别ck中出现的次数,V是所有类别的词项集合。这里对词的位置作了独立性假设,即两个词只要它们出现的次数一样,那不管它们在文档的出现位置,它们大概率值P(tj|ck)都是一样,这个位置独立性假设与现实很不相符,比如“放马屁”跟“马放屁”表述的是不同的内容,但实践发现,位置独立性假设得到的模型准确率并不低,因为大多数文本分类都是靠词的差异来区分,而不是词的位置,如果考虑词的位置,那么问题将表达相当复杂,以至于我们无从下手。


然后需要注意的一个问题是ti可能没有出现在ck类别的训练集,却出现在ck类别的测试集合中,这样因为Tik为0,导致连乘概率值都为0,其他特征词出现得再多,该文档也不会被分到ck类别,而且在对数累加的情况下,0值导致计算错误,处理这种问题的方法是采样加1平滑,即认为每个词在各个类别中都至少出现过一次,即


数据挖掘(8):朴素贝叶斯分类算法原理与实践


下面这个例子来自于参考文献1,假设有如下的训练集合测试集:


数据挖掘(8):朴素贝叶斯分类算法原理与实践


现在要计算docID为5的测试文档是否属于China类别,首先计算个各类的概率,P(c=China)=3/4,P(c!=China)=1/4,然后计算各个类中词项的概率:


数据挖掘(8):朴素贝叶斯分类算法原理与实践


注意分母(8+6)中8表示China类的词项出现的总次数是8,+6表示平滑,6是总词项的个数,然后计算测试文档属于各个类别的概率:


数据挖掘(8):朴素贝叶斯分类算法原理与实践


可以看出该测试文档应该属于CHina类别。


文本分类实践


我找了搜狗的搜狐新闻数据的历史简洁版,总共包括汽车、财经、it、健康等9类新闻,一共16289条新闻,搜狗给的数据是每一篇新闻用一个txt文件保存,我预处理了一下,把所有的新闻文档保存在一个文本文件中,每一行是一篇新闻,同时保留新闻的id,id的首字母表示类标,预处理并分词后的示例如下:



我用6289条新闻作为训练集,剩余1万条用于测试,采用互信息进行文本特征的提取,总共提取的特征词是700个左右。


分类的结果如下:




8343 10000 0.8343



总共10000条新闻,分类正确的8343条,正确率0.8343,这里主要是演示贝叶斯的分类过程,只考虑了正确率也没有考虑其他评价指标,也没有进行优化。贝叶斯分类的效率高,训练时,只需要扫描一遍训练集,记录每个词出现的次数,以及各类文档出现的次数,测试时也只需要扫描一次测试集,从运行效率这个角度而言,朴素贝叶斯的效率是最高的,而准确率也能达到一个理想的效果。


我的实现代码如下:





#!encoding=utf-8


import random


import sys


import math


import collections


import sys


def shuffle():



'''将原来的文本打乱顺序,用于得到训练集和测试集'''


datas = [line.strip() for line in sys.stdin]


random.shuffle(datas)


for line in datas:


print line




lables = ['A','B','C','D','E','F','G','H','I']


def lable2id(lable):


for i in xrange(len(lables)):


if lable == lables[i]:


return i


raise Exception('Error lable %s' % (lable))



def docdict():


return [0]*len(lables)



def mutalInfo(N,Nij,Ni_,N_j):



#print N,Nij,Ni_,N_j


return Nij * 1.0 / N * math.log(N * (Nij+1)*1.0/(Ni_*N_j))/ math.log(2)



def countForMI():



'''基于统计每个词在每个类别出现的次数,以及每类的文档数'''


docCount = [0] * len(lables)


#每个类的词数目


wordCount = collections.defaultdict(docdict)


for line in sys.stdin:


lable,text = line.strip().split(' ',1)


index = lable2id(lable[0])


words = text.split(' ')


for word in words:


wordCount[word][index] += 1


docCount[index] += 1



miDict = collections.defaultdict(docdict)


#互信息值


N = sum(docCount)


for k,vs in wordCount.items():


for i in xrange(len(vs)):


N11 = vs[i]


N10 = sum(vs) - N11


N01 = docCount[i] - N11


N00 = N - N11 - N10 - N01


mi = mutalInfo(N,N11,N10+N11,N01+N11) + mutalInfo(N,N10,N10+N11,N00+N10)+ mutalInfo(N,N01,N01+N11,N01+N00)+ mutalInfo(N,N00,N00+N10,N00+N01)


miDict[k][i] = mi


fWords = set()


for i in xrange(len(docCount)):


keyf = lambda x:x[1][i]


sortedDict = sorted(miDict.items(),key=keyf,reverse=True)


for j in xrange(100):


fWords.add(sortedDict[j][0])


print docCount


#打印各个类的文档数目


for fword in fWords:


print fword




def loadFeatureWord():



'''导入特征词'''


f = open('feature.txt')


docCounts = eval(f.readline())


features = set()


for line in f:


features.add(line.strip())


f.close()


return docCounts,features



def trainBayes():



'''训练贝叶斯模型,实际上计算每个类中特征词的出现次数'''


docCounts,features = loadFeatureWord()


wordCount = collections.defaultdict(docdict)


tCount = [0]*len(docCounts)


#每类文档特征词出现的次数


for line in sys.stdin:


lable,text = line.strip().split(' ',1)


index = lable2id(lable[0])


words = text.split(' ')


for word in words:


if word in features:


tCount[index] += 1


wordCount[word][index] += 1


for k,v in wordCount.items():


scores = [(v[i]+1) * 1.0 / (tCount[i]+len(wordCount)) for i in xrange(len(v))]


#加1平滑


print '%s\t%s' % (k,scores)



def loadModel():



'''导入贝叶斯模型'''


f = open('model.txt')


scores = {}


for line in f:


word,counts = line.strip().rsplit('\t',1)


scores[word] = eval(counts)


f.close()


return scores



def predict():



'''预测文档的类标,标准输入每一行为一个文档'''


docCounts,features = loadFeatureWord()


docscores = [math.log(count * 1.0 /sum(docCounts)) for count in docCounts]


scores = loadModel()


rCount = 0


docCount = 0


for line in sys.stdin:


lable,text = line.strip().split(' ',1)


index = lable2id(lable[0])


words = text.split(' ')


preValues = list(docscores)


for word in words:


if word in features:


for i in xrange(len(preValues)):


preValues[i]+=math.log(scores[word][i])


m = max(preValues)


pIndex = preValues.index(m)


if pIndex == index:


rCount += 1


print lable,lables[pIndex],text


docCount += 1


print rCount,docCount,rCount * 1.0 / docCount




if __name__=="__main__":



#shuffle()



#countForMI()



#trainBayes()


predict()





代码里面,计算特征词与训练模型、测试是分开的,需要修改main方法,比如计算特征词:




$cat train.txt | python bayes.py > feature.txt



训练模型:




$cat train.txt | python bayes.py > model.txt



预测模型:




cat test.txt | python bayes.py > predict.out



总结


本文介绍了朴素贝叶斯分类方法,还以文本分类为例,给出了一个具体应用的例子,朴素贝叶斯的朴素体现在条件变量之间的独立性假设,应用到文本分类上,作了两个假设,一是各个特征词对分类的影响是独立的,另一个是词项在文档中的顺序是无关紧要的。朴素贝叶斯的独立性假设在实际中并不成立,但在分类效上依然不错,加上独立性假设后,对与属于类ck的谋篇文档d,其p(ck|d)往往会估计过高,即本来预期p(ck|d)=0.55,而朴素贝叶斯却计算得到p(ck|d)=0.99,但这并不影响分类结果,这是朴素贝叶斯分类器在文本分类上效果优于预期的原因。


参考文献:




  • 王斌 译.信息检索导论. 人民邮电出版社


  • codemeals. 文本特征选择. cnblogs.


  • 李航.统计学习方法.清华大学出版社


  • 陈希孺. 概率论与数理统计.中国科学技术出版社.





Python开发者

--------------------------------------

投稿网址:top.jobbole.com

商务合作QQ:2302462408



推荐阅读
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 本文介绍了在Python3中如何使用选择文件对话框的格式打开和保存图片的方法。通过使用tkinter库中的filedialog模块的asksaveasfilename和askopenfilename函数,可以方便地选择要打开或保存的图片文件,并进行相关操作。具体的代码示例和操作步骤也被提供。 ... [详细]
  • 本文介绍了C++中省略号类型和参数个数不确定函数参数的使用方法,并提供了一个范例。通过宏定义的方式,可以方便地处理不定参数的情况。文章中给出了具体的代码实现,并对代码进行了解释和说明。这对于需要处理不定参数的情况的程序员来说,是一个很有用的参考资料。 ... [详细]
  • HDFS2.x新特性
    一、集群间数据拷贝scp实现两个远程主机之间的文件复制scp-rhello.txtroothadoop103:useratguiguhello.txt推pushscp-rr ... [详细]
  • 也就是|小窗_卷积的特征提取与参数计算
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了卷积的特征提取与参数计算相关的知识,希望对你有一定的参考价值。Dense和Conv2D根本区别在于,Den ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 本文讨论了编写可保护的代码的重要性,包括提高代码的可读性、可调试性和直观性。同时介绍了优化代码的方法,如代码格式化、解释函数和提炼函数等。还提到了一些常见的坏代码味道,如不规范的命名、重复代码、过长的函数和参数列表等。最后,介绍了如何处理数据泥团和进行函数重构,以提高代码质量和可维护性。 ... [详细]
  • Java SE从入门到放弃(三)的逻辑运算符详解
    本文详细介绍了Java SE中的逻辑运算符,包括逻辑运算符的操作和运算结果,以及与运算符的不同之处。通过代码演示,展示了逻辑运算符的使用方法和注意事项。文章以Java SE从入门到放弃(三)为背景,对逻辑运算符进行了深入的解析。 ... [详细]
author-avatar
林子冰2011
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有