《机器学习实战》学习笔记:基于朴素贝叶斯的分类方法
2015-09-12 00:02
519 查看
概率是许多机器学习算法的基础,在前面生成决策树的过程中使用了一小部分关于概率的知识,即统计特征在数据集中取某个特定值的次数,然后除以数据集的实例总数,得到特征取该值的概率。
目录:
一.基于贝叶斯理论的分类方法
二.关于朴素贝叶斯的应用场景
三.基于Python和朴素贝叶斯的文本分类
1.准备数据
2.训练算法
3.测试算法
四.小结
以下进入正文:
一.基于贝叶斯理论的分类方法
假设有两类数据组成的数据集如下:
其中,假设两个概率分布的参数已知,并用
贝叶斯决策理论的核心思想是:选择高概率所对应的类别,选择具有最高概率的决策。有时也被总结成“多数占优”的原则。
具体到实例,对于一个数据点
若
若
当然,在实际情况中,单单依靠以上的判定无法解决所有的问题,因为以上准则还不是贝叶斯决策理论的所有内容,使用
则以上判定法则可转化为:
若
若
二.关于朴素贝叶斯的应用场景
机器学习的一个重要应用就是文档的自动分类,而朴素贝叶斯正是文档分类的常用算法。基本步骤是遍历并记录下文档中出现的词,并把每个词的出现或者不出现作为一个特征。这样便有跟文档中出现过词汇的个数一样多的特征。若有大量特征时,使用直方图效果更好。以下是朴素贝叶斯的一般过程:
收集数据:这里使用RSS源
准备数据:需要数值型&布尔型数据
分析数据:有大量特征时,绘制特征的作用不大,此时使用直方图效果更好
训练算法:计算不同的独立特征的条件概率
测试算法:计算错误率
使用算法:如文档分类
讲到这里,你也许还会带着疑问,为什么贝叶斯前会加上“朴素”,其实,这是基于朴素贝叶斯的一个假设,即:特征之间相互(统计意义上)独立,如一个单词出现的可能性与其他单词相邻没有关系,当然这在实际情况中不一定是正确的,但无数实验表明,这种假设是有必要的,而且朴素贝叶斯的实际效果其实很好。
朴素贝叶斯的另外一个假设是:每个特征同等重要。当然,这个假设也有问题(不然就不叫假设了……),但确实有用的假设。
三.基于Python和朴素贝叶斯的文本分类
从文本中提取特征,首先需要将文本进行拆分,转化为词向量,某个词存在表示为1,不存在表示为0,这样,原来一大串字符串便转为简单的0,1序列的向量。这种情况下只考虑某个词是否出现,当然,你也可以使用记录词的出现次数作为向量,或者记录不同词出现的频率等等。
1.准备数据:从文本中构建词向量,这里考虑出现在所有文档中的所有单词,并将每一篇文档转化为词汇表上的向量。下面的代码实现了功能,其中:
函数
函数
函数
2.训练算法:从词向量计算概率,将之前的贝叶斯准则中的
计算分为类别
已知某个类别c,计算w在类别
伪代码如下:
贝叶斯分类器训练函数代码如下:
3.测试算法:测试分类器的效果
在
最后,对两组word串进行检测,第一段被判定为非侮辱性用语,而第二段则被判定为侮辱性用语,分类正确。
四.小结
以上实验基本实现了朴素贝叶斯分类器,并正确执行了文本分类,后面要进一步学习,将朴素贝叶斯运用到垃圾邮件过滤、个人广告获取区域倾向等实际应用。
目录:
一.基于贝叶斯理论的分类方法
二.关于朴素贝叶斯的应用场景
三.基于Python和朴素贝叶斯的文本分类
1.准备数据
2.训练算法
3.测试算法
四.小结
以下进入正文:
一.基于贝叶斯理论的分类方法
假设有两类数据组成的数据集如下:
其中,假设两个概率分布的参数已知,并用
p1(x,y)表示当前数据点
(x,y)属于类别一的概率;用
p2(x,y)表示当前数据点
(x,y)属于类别二的概率。
贝叶斯决策理论的核心思想是:选择高概率所对应的类别,选择具有最高概率的决策。有时也被总结成“多数占优”的原则。
具体到实例,对于一个数据点
(x,y),可以用如下规则判定它的类别:
若
p1(x,y)>p2(x,y),那么点
(x,y)被判定为类别一。
若
p1(x,y)<p2(x,y),那么点
(x,y)被判定为类别二。
当然,在实际情况中,单单依靠以上的判定无法解决所有的问题,因为以上准则还不是贝叶斯决策理论的所有内容,使用
p1(x,y)和
p2(x,y)只是为了简化描述。更多的,我们使用
p(ci|x,y)来确定给定坐标的点
(x,y),该数据点来自类别
ci的概率是多少。具体地,应用贝叶斯准则可得到,该准则可以通过已知的三个概率值来计算未知的概率值:
则以上判定法则可转化为:
若
p(c1|x,y)>p(c2|x,y),那么点
(x,y)被判定为类别一。
若
p(c1|x,y)<p(c2|x,y),那么点
(x,y)被判定为类别二。
二.关于朴素贝叶斯的应用场景
机器学习的一个重要应用就是文档的自动分类,而朴素贝叶斯正是文档分类的常用算法。基本步骤是遍历并记录下文档中出现的词,并把每个词的出现或者不出现作为一个特征。这样便有跟文档中出现过词汇的个数一样多的特征。若有大量特征时,使用直方图效果更好。以下是朴素贝叶斯的一般过程:
收集数据:这里使用RSS源
准备数据:需要数值型&布尔型数据
分析数据:有大量特征时,绘制特征的作用不大,此时使用直方图效果更好
训练算法:计算不同的独立特征的条件概率
测试算法:计算错误率
使用算法:如文档分类
讲到这里,你也许还会带着疑问,为什么贝叶斯前会加上“朴素”,其实,这是基于朴素贝叶斯的一个假设,即:特征之间相互(统计意义上)独立,如一个单词出现的可能性与其他单词相邻没有关系,当然这在实际情况中不一定是正确的,但无数实验表明,这种假设是有必要的,而且朴素贝叶斯的实际效果其实很好。
朴素贝叶斯的另外一个假设是:每个特征同等重要。当然,这个假设也有问题(不然就不叫假设了……),但确实有用的假设。
三.基于Python和朴素贝叶斯的文本分类
从文本中提取特征,首先需要将文本进行拆分,转化为词向量,某个词存在表示为1,不存在表示为0,这样,原来一大串字符串便转为简单的0,1序列的向量。这种情况下只考虑某个词是否出现,当然,你也可以使用记录词的出现次数作为向量,或者记录不同词出现的频率等等。
1.准备数据:从文本中构建词向量,这里考虑出现在所有文档中的所有单词,并将每一篇文档转化为词汇表上的向量。下面的代码实现了功能,其中:
函数
loadDataSet()创建了一些实验样本
postingList和对应的标签
listClass,有一些样本被标签为带有侮辱性文字;
函数
createNonRepeatedList()统计并保存一个列表
vocList,该列表包含所有文档中出现的词(不重复),这里使用了Python的
set函数;
函数
detectInput(vocList, inputStream)使用了词列表
vocList,
inputStream为待检测的word串,输出文档向量,向量的每一元素为
1或
0,分别表示词汇表中的单词在输入文档中是否出现。
# -*- coding: utf-8 -*- """ Created on Tue Sep 08 16:12:55 2015 @author: Administrator """ from numpy import * # 创建实验样本,可能需要对真实样本做一些处理,如去除标点符号 def loadDataSet(): postingList=[['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'], ['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'], ['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'], ['stop', 'posting', 'stupid', 'worthless', 'garbage'], ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'], ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']] listClass = [0, 1, 0, 1, 0, 1] # 1代表存在侮辱性的文字,0代表不存在 return postingList, listClass # 将所有文档所有词都存到一个列表中,用set()函数去除重复出现的词 def createNonRepeatedList(data): vocList = set([]) for doc in data: vocList = vocList | set(doc) # 两集合的并集 return list(vocList) def detectInput(vocList, inputStream): returnVec = [0]*len(vocList) # 创建和vocabList一样长度的全0列表 for word in inputStream: if word in vocList: # 针对某段words进行处理 returnVec[vocList.index(word)] = 1 # ? else: print "The word :%s is not in the vocabulary!" % word return returnVec
2.训练算法:从词向量计算概率,将之前的贝叶斯准则中的
(x,y)改为向量
w, 其长度为词向量的长度,如以下公式:
计算分为类别
ci的概率
p(ci)。通过类别i中的文档数除以总的文档数可计算。及
label_i/sum(label)。
已知某个类别c,计算w在类别
ci中的概率
p(w|ci)。由于朴素贝叶斯假设所有特征相互独立,故有:
p(w|ci) = p(w0,w1,...,wn|ci) = p(w0|ci)*p(w1|ci)*...*p(w0|ci)计算每个词wj在已知类别i的概率,然后再相乘。
伪代码如下:
计算每个类别中的文档数目 对每篇训练文档: 对每个类别: 如果词条出现在文档中 -> 增加该词条的计数值 增加所有词条的计数值 对每个类别: 将该词条的数目除以总词条数目得到条件概率 返回每个类别的条件概率
贝叶斯分类器训练函数代码如下:
def trainNaiveBayes(trainMatrix, classLabel): numTrainDocs = len(trainMatrix) numWords = len(trainMatrix[0]) pBase = sum(classLabel) / float(numTrainDocs) # The following Settings aim at avoiding the probability of 0 p0Num = ones(numWords) p1Num = ones(numWords) p0Denom = 2.0 p1Denom = 2.0 for i in range(numTrainDocs): if classLabel[i] == 1: p1Num += trainMatrix[i] p1Denom += sum(trainMatrix[i]) else: p0Num += trainMatrix[i] p0Denom += sum(trainMatrix[i]) p0 = log(p0Num / p0Denom) p1 = log(p1Num / p1Denom) return p0, p1, pBase
3.测试算法:测试分类器的效果
在
p(w0|ci)*p(w1|ci)*...p(w0|ci)中,如果某个值为0,则会使得最后的乘积为0,故将所有词初始化为至少出现一次。分母初始化为2,这样不改变实际效果。同时,
p(w0|ci)*p(w1|ci)*...*p(w0|ci)取对数,得到:
ln(p(w0|ci))+ln(p(w1|ci))+...+ln(p(w0|ci)), 由于对数函数
ln(x)为单调递增函数,因此在计算过程中对乘法取对数对概率曲线的单调性没有影响(高等数学中常用的性质)。修改代码后进行测试:
def trainNaiveBayes(trainMatrix, classLabel): numTrainDocs = len(trainMatrix) numWords = len(trainMatrix[0]) pBase = sum(classLabel) / float(numTrainDocs) # The following Settings aim at avoiding the probability of 0 p0Num = ones(numWords) p1Num = ones(numWords) p0Denom = 2.0 p1Denom = 2.0 for i in range(numTrainDocs): if classLabel[i] == 1: p1Num += trainMatrix[i] p1Denom += sum(trainMatrix[i]) else: p0Num += trainMatrix[i] p0Denom += sum(trainMatrix[i]) p0 = log(p0Num / p0Denom) p1 = log(p1Num / p1Denom) return p0, p1, pBase
trainMat = []
for doc in loadData:
trainMat.append(detectInput(vocList, doc))
p0,p1,pBase = trainNaiveBayes(trainMat, dataLabel)
#print "trainMat : "
#print trainMat
# test the algorithm
def naiveBayesClassify(vec2Classify, p0, p1, pBase):
p0res = sum(vec2Classify * p0) + log(1 - pBase)
p1res = sum(vec2Classify * p1) + log(pBase)
if p1res > p0res:
return 1
else:
return 0
def testNaiveBayes():
loadData, classLabel = loadDataSet()
vocList = createNonRepeatedList(loadData)
trainMat = []
for doc in loadData:
trainMat.append(detectInput(vocList, doc))
p0, p1, pBase = trainNaiveBayes(array(trainMat), array(classLabel))
testInput = ['love', 'my', 'dalmation']
thisDoc = array(detectInput(vocList, testInput))
print testInput, 'the classified as: ', naiveBayesClassify(thisDoc, p0, p1, pBase)
testInput = ['stupid', 'garbage']
thisDoc = array(detectInput(vocList, testInput))
print testInput, 'the classified as: ', naiveBayesClassify(thisDoc, p0, p1, pBase)
testNaiveBayes()
最后,对两组word串进行检测,第一段被判定为非侮辱性用语,而第二段则被判定为侮辱性用语,分类正确。
四.小结
以上实验基本实现了朴素贝叶斯分类器,并正确执行了文本分类,后面要进一步学习,将朴素贝叶斯运用到垃圾邮件过滤、个人广告获取区域倾向等实际应用。
相关文章推荐
- Yii2框架中一些折磨人的坑
- PHP比C/C++或Java少了什么?多线程,多线程,多线程……
- 为什么是“程序猿”而不是“程序媛”?
- Sublime Text3技巧使用
- Node.js
- Sublime Text
- P2P网贷理财入门知识
- 不必放大融金所事件对P2P行业影响
- 投资理财五字秘诀
- JAVA String类与常量池,堆之间的错综复杂...
- 关于引入第三方jar包引发的java.lang.NoClassDefFoundError解决
- Python读取中文txt乱码问题
- MAC OSX 下安装 CTAGS
- 7.html中的表单元素一
- zookeeper 典型应用场景-集群管理
- 安装与配置windbg的symbol(符号)
- windows 2008 64位iis 配置php
- apache 日志不记录图片 css js 文件访问
- 处理一次挂马案例-代码整理
- 利用Nginx 做反向代理替换掉页面部分内容