基于Python的朴素贝叶斯算法实现
来源:互联网 发布:域名后缀为 .qq.com 编辑:程序博客网 时间:2024/05/01 12:21
本文主要介绍了贝叶斯算法的基本原理以及基于Python的朴素贝叶斯分类算法的实现。
贝叶斯定理
我们先从理论方面来讲讲著名的贝叶斯定理- 条件概率
条件概率(又称后验概率)就是事件A在另外一个事件B已经发生条件下的发生概率。条件概率表示为P(A|B),读作“在B条件下A的概率”。
比如,在同一个样本空间Ω 中的事件或者子集A与B,如果随机从Ω 中选出的一个元素属于B,那么这个随机选择的元素还属于A的概率就定义为在B的前提下A的条件概率,所以:P(A|B)=|A∩B||B| ,接着分子、分母都除以Ω 得到:P(A|B)P(A∩B)P(B) - 联合概率
联合概率表示两个事件共同发生的概率,如:A与B的联合概率表示为P(A∩B) 或者P(A,B) - 边缘概率(先验概率)
边缘概率是某个事件发生的概率。在联合概率中,把最终结果中那些不需要的事件通过合并成它们的全概率,而消去它们(对离散随机变量用求和得全概率,对连续随机变量用积分得全概率),这称为边缘化(marginalization),比如A的边缘概率表示为P(A) ,B的边缘概率表示为P(B) 。 - 贝叶斯公式
首先,在事件B发生之前,我们对事件A的发生有一个基本的概率判断,称为A的先验概率,用P(A) 表示;同理,事件B的先验概率可用P(B) 表示。
在事件B发生之后,我们对事件A的发生概率重新评估,称为A的后验概率,用P(A|B) 表示;同理,事件B的后验概率为P(B|A)
根据条件概率的定义,在事件B发生的条件下事件A发生的概率是:P(A|B)=P(A∩B)P(B)
同理,事件A发生的条件下时间B发生的概率是:P(B|A)=P(A∩B)P(A)
整理与合并上述两条等式,便可以得到:P(A|B)P(B)=P(A∩B)=P(B|A)P(A)
若P(B) 非零,我们便可以得到贝叶斯定理的表达式:P(A|B)=P(A)P(B|A)P(B)
应用:如
P(A)=0.5 表示的是酒后驾驶的概率为0.5 ,P(B)=0.1 表示的是交警抽查的概率(但要注意的是,条件A和条件B是相互独立的),那么P(B|A)=P(A)×P(B)=0.05 则表示酒后驾驶被交警抽查到的概率为0.05。那么问题来了,已知一老司机被交警抽查到了,那么我们就可以用贝叶斯定理求出他酒后驾驶的概率(P(A|B) )是多少了。- 条件概率
朴素贝叶斯分类
目前最为广泛的两种分类模型是决策树模型(Decision Tree Model)和朴素贝叶斯模型(Naive Bayesian Model,NBM)。而朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设的分类方法。朴素贝叶斯分类器基于一个“朴素”的假定:给定目标值时属性之间相互条件独立。基于这个假定和贝叶斯定理,我们就可以在P(A|B) 和P(B|A) 间进行转换。
就文本分类而言,它认为每个词袋中的两两词之间的关系是相互独立的,因此得到了朴素贝叶斯的定义:- 设
x={a1,a2,⋯,am} 为一个待分类项,而每个a 为x 的一个特征属性。 - 有类别集合
C={y1,y2,⋯,yn} 。 - 计算
P(y1|x),P(y2|x),⋯,P(yn|x) 。 - 如果
P(yk|x)=max{P(y1|x),P(y2|x),⋯,P(yn|x)} ,则x∈yk 。
那么问题来了,关键的第3步如何进行计算?
(1) 找到一个已知分类的待分类项集合(也就是训练集);
(2) 统计得到在各个类别下各个特征属性的条件概率估计,即:P(a1|y1),P(x2|y1),⋯,P(am|y1);P(a1|y2),P(x2|y2),⋯,P(am|y2);⋮P(a1|yn),P(x2|yn),⋯,P(am|yn);
(3)如果各个特征属性是条件独立的(或者假设它们之间是相互独立的),则根据贝叶斯定理有如下推导:P(yi|x)=P(x|yi)P(yi)P(x)
因为分母对于所有类别为常数,只要将分子最大化皆可。又因为诶各特征属性是条件独立的,所以有:P(x|yi)P(yi)=P(a1|y1)P(a2|y2)⋯P(am|yi)P(yi)=P(yi)∏j=1mP(aj|yi)
根据上述分析,朴素贝叶斯分类的流程可以表示如下:- 训练数据产生训练样本集:TF-IDF;
- 对每个类别计算
P(yi) ; - 对每个特征属性计算所有划分的条件概率;
- 对每个类别计算
P(x|yi)P(yi) ; - 以
P(x|yi)P(yi) 的最大项作为x的所属类别。
所谓的TF-IDF就是词频逆文档频率,如果某个词或短语在一篇文章中出现的频率高,并且在其他文章中很少出现,则认为此词或短语具有很好的类别区分能力,适合用来分类。- 词频(Term Frequency, TF)指的是某一个给定的词语在该文档中出现的频率。这个数字是对词数(Term Count)的归一化,以防止它偏向长的文件。对于在某一特定文件里的词语来说,它的重要性可表示为:
TFij=ni,j∑knk,j
其中,ni,j 是该词在文件中出现的次数,∑knk,j 是文件中所有字词的出现次数之和。 - 逆向文件频率(Inverse Document Frequency, IDF)是一个词语普遍重要性的度量。某一特定词语的IDF,可以由总文件数目除以包含该词语的文件的数目,再将得到的商取对数得到:
IDFi=log∣D∣∣j:ti∈dj∣
其中,∣D∣ 表示语料库中的文件总数;j 包含词语的文件数目(如果该词语不在语料库中,就会导致分母为零,因此一般情况下使用1+∣d∈D:t∈d∣ 作为分母)。 - TF-IDF权重策略就是计算TF与IDF的乘积,某一特定文件内的高词语频率,以及该词语在整个文件集合中的低文件频率(
TFIDFij=TFijI×IDFij ),可以产生高权重的TF-IDF。因此,TF-IDF倾向于过滤掉常见的词语,保持重要的词语。
- 词频(Term Frequency, TF)指的是某一个给定的词语在该文档中出现的频率。这个数字是对词数(Term Count)的归一化,以防止它偏向长的文件。对于在某一特定文件里的词语来说,它的重要性可表示为:
- 设
代码实现
- 创建简单的英文语料作为数据集
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','my'],\ ['stop', 'posting', 'stupid', 'worthless', 'garbage']\ ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],\ ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']] classVec = [0,1,0,1,0,1] #1 is abusive, 0 not return postingList,classVec
postingList是训练集文本,classVec是每个文本对应的分类。
编写一个贝叶斯算法类,创建默认的构造方法
class NBayes(object): def __init__(self): self.vocabulary = [] # 词典 self.idf=0 # 词典的idf权值向量 self.tf=0 # 训练集的权值矩阵 self.tdm=0 # P(x|yi) self.Pcates = {} # P(yi)--是个类别字典 self.labels=[] # 对应每个文本的分类,是个外部导入的列表 self.doclength = 0 # 训练集文本 self.vocablen = 0 # 词典词长 self.testset = 0 # 测试集
导入训练集,生成算法参数和数据结构
def train_set(self,trainset,classVec): self.cate_prob(classVec) # 计算每个分类在数据集中的概率:P(yi) self.doclength = len(trainset) tempset = set() [tempset.add(word) for doc in trainset for word in doc ] # 生成词典 self.vocabulary = list(tempset) self.vocablen = len(self.vocabulary) self.calc_wordfreq(trainset) # 计算词频数据集 self.build_tdm() # 按分类累计向量空间的每维值:P(x|yi)
计算在数据集中每个分类的高铝
P(yi) 的cate_prob函数def cate_prob(self,classVec): self.labels = classVec labeltemps = set(self.labels) # 获取全部分类 for labeltemp in labeltemps: # 统计列表中重复的分类: self.labels.count(labeltemp) self.Pcates[labeltemp] = float(self.labels.count(labeltemp))/float(len(self.labels))
生成普通的词频向量的calc_wordfreq函数
# 生成普通的词频向量def calc_wordfreq(self,trainset): self.idf = np.zeros([1,self.vocablen]) # 1*词典数 self.tf = np.zeros([self.doclength,self.vocablen]) # 训练集文件数*词典数 for indx in xrange(self.doclength): # 遍历所有的文本 for word in trainset[indx]: # 遍历文本中的每个词 self.tf[indx,self.vocabulary.index(word)] +=1 # 找到文本的词在字典中的位置+1 for signleword in set(trainset[indx]): self.idf[0,self.vocabulary.index(signleword)] +=1
按分类累计计算向量空间的每维值
P(x|yi) 的build_tdm函数#按分类累计向量空间的每维值:P(x|yi)def build_tdm(self): self.tdm = np.zeros([len(self.Pcates),self.vocablen]) #类别行*词典列 sumlist = np.zeros([len(self.Pcates),1]) # 统计每个分类的总值 for indx in xrange(self.doclength): # 将同一类别的词向量空间值加总 self.tdm[self.labels[indx]] += self.tf[indx] # 统计每个分类的总值--是个标量 sumlist[self.labels[indx]]= np.sum(self.tdm[self.labels[indx]]) self.tdm = self.tdm/sumlist # 生成P(x|yi)
将测试集映射到当前词典的map2vocab函数
def map2vocab(self,testdata): self.testset = np.zeros([1,self.vocablen]) for word in testdata: self.testset[0,self.vocabulary.index(word)] +=1
预测分类结果,输出预测的分类类别的predict函数
def predict(self,testset): if np.shape(testset)[1] != self.vocablen: # 如果测试集长度与词典不相等,退出程序 print "输入错误" exit(0) predvalue = 0 # 初始化类别概率 predclass = "" # 初始化类别名称 for tdm_vect,keyclass in zip(self.tdm,self.Pcates): # P(x|yi) P(yi) # 变量tdm,计算最大分类值 temp = np.sum(testset*tdm_vect*self.Pcates[keyclass]) if temp > predvalue: predvalue = temp predclass = keyclass return predclass
使用TF-IDF策略改进算法
# 以生成 tf-idf方式生成向量空间的calc_tfidf函数def calc_tfidf(self,trainset): self.idf = np.zeros([1,self.vocablen]) self.tf = np.zeros([self.doclength,self.vocablen]) for indx in xrange(self.doclength): for word in trainset[indx]: self.tf[indx,self.vocabulary.index(word)] +=1 # 消除不同句长导致的偏差 self.tf[indx] = self.tf[indx]/float(len(trainset[indx])) for signleword in set(trainset[indx]): self.idf[0,self.vocabulary.index(signleword)] +=1 self.idf = np.log(float(self.doclength)/self.idf) self.tf = np.multiply(self.tf,self.idf) # 矩阵与向量的点乘 tf x idf
分类结果
# -*- coding: utf-8 -*-import sysimport osfrom numpy import *import numpy as npfrom Nbayes_lib import *dataSet,listClasses = loadDataSet() # 导入外部数据集# dataset: 句子的词向量# listClass是句子所属的类别 [0,1,0,1,0,1]nb = NBayes() # 实例化nb.train_set(dataSet,listClasses) # 训练数据集nb.map2vocab(dataSet[0]) # 随机选择一个测试句print nb.predict(nb.testset) # 输出分类结果
分类结果为:
1
- 创建简单的英文语料作为数据集
- 基于Python的朴素贝叶斯算法实现
- 基于Hadoop的朴素贝叶斯算法实现
- 朴素贝叶斯算法的python实现
- 朴素贝叶斯分类算法的Python实现
- 《机器学习实战》基于朴素贝叶斯分类算法构建文本分类器的Python实现
- 朴素贝叶斯算法Python实现
- 朴素贝叶斯算法--python实现
- 机器学习算法-朴素贝叶斯Python实现
- 朴素贝叶斯分类算法python实现
- 基于朴素贝叶斯的文本分类算法
- 基于朴素贝叶斯的内容推荐算法
- 基于朴素贝叶斯的内容推荐算法
- 基于朴素贝叶斯的文本分类算法
- 基于朴素贝叶斯的文本分类算法
- 朴素贝叶斯python实现
- Python实现朴素贝叶斯
- 朴素贝叶斯&&Python实现
- Python实现朴素贝叶斯
- sleep、yield、wait、join的区别
- Android源码的下载、编译与导入到Android Studio
- Collection类的用法
- 不做苦逼的程序员
- Linux运维高薪入门及进阶全新经典视频-老男孩Linux(免费)
- 基于Python的朴素贝叶斯算法实现
- Android开发之本地音乐播放器(增强版)
- 一道企业shell编程实战题-看看谁能快速搞定
- 打印杨辉三角
- 计数排序 练习题
- 海量数据的KNN分类、Kmeans聚类
- LaTeX技巧002:实现右上角的圆圈度数
- 342.[leetcode]Power of four
- 开发shell脚本检查Nginx实战分享