分类算法——朴素贝叶斯算法python实现(文末附工程代码)

前言

朴素贝叶斯是一种十分简单的分类算法,称其朴素是因为其思想基础的简单性,就文本分类而言,他认为词袋中的两两词之间的关系是相互独立的,即一个对象的特征向量中的每个维度都是互相独立的。这是朴素贝叶斯理论的思想基础。

贝叶斯公式推导

朴素贝叶斯分类的正式定义:

  1. 设x={}为一个待分类项,而每个a为x的一个特征属性
  2. 有类别集合C={}
  3. 计算P(|x),P(|x),…,P(|x)
  4. 如果P(|x)=max{ P(|x),P(|x),…,P(|x)},则x

那么关键就是如何计算第三步中的各个条件概率,我们可以这样计算:

  1. 找到一个已知分类的待分类项集合,即训练集
  2. 统计得到在各类别下各个特征属性的条件概率估计,即:

P(),P(),…,P()

P(),P(),…,P()

P(),P(),…,P()

  1. 如果各个特征属性是条件独立的(或者假设他们之间是相互独立的),根据贝叶斯定理,有如下推导:

因为分母对于所有类别为常数,只要将分子最大化即可,又因为各特征属性是条件独立的,所以有:

根据上述分析,朴素贝叶斯分类的流程可以表示如下:

  1. 训练数据生成样本集:TF-IDF
  2. 对每个类别计算P()
  3. 对每个特征属性计算所有划分的条件概率
  4. 对每个类别计算P(x|)P()
  5. 以P(x|)P()的最大项作为x的所属类别

朴素贝叶斯的算法实现

首先创建一个Nbayes_pre.py文件来编写导入的数据和朴素贝叶斯类的代码

  1. 使用简单的英文语料作为数据集合,其中postingList是训练集文本,classVec是每个文本对应的分类

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','steak','how','to','stop','hime'],
                 ['quit','buying','worthless','dog','food','stupid']]
    classVec=[0,1,0,1,0,1]#1 is abusive, 0 not
   
return postingList,classVec

  1. 下面逐步实现贝叶斯算法,第一步即编写一个贝叶斯算法类,并创建默认的构造方法
class NBayes(object):
    def _init_(self):
        self.vocabulary=[]#词典
       
self.idf=0#词典的IDF权重向量
       
self.tf=0#训练集的权值矩阵
       
self.tdm=0#P(x│y_i)
       
self.Pcates={}#P(y_i)是一个类别字典
       
self.labels=[]#对应每个文本的分类,是一个外部导入的列表
       
self.doclength=0#训练集文本数
       
self.vocablen=0#词典词长
       
self.testset=0#测试集
  1. 导入和训练数据集,生成算法必须的参数和数据结构
def train_set(self,trainset,classVec):
    self.cate_prob(classVec)#计算每个分类在数据集中的概率P(y_i)
   
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|y_i)
  1. 计算在数据集中每个分类的概率P(y_i)
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))
  1. 生成普通的词频向量
def calc_wordfreq(self,trainset):
    self.idf=np.zeros([1,self.vocablen])#1x词典数
   
self.tf=np.zeros([self.doclength,self.vocablen])#训练集文件数x词典数
   
for indx in xrange(self.doclength):#遍历所有文本
       
for word in trainset[indx]:#遍历文本中的每个词
            #找到文本的词在字典中的位置+1
           
self.tf[indx,self.vocabulary.index(word)]+=1
        for signleword in set(trainset[indx]):
            self.idf[0,self.vocabulary.index(signleword)]+=1
  1. 按分类累计计算向量空间的每维值P(x|y_i)
def build_tdm(self):
    self.tdm=np.zeros([len(self.Pcates),self.vocablen])#类别行x词典列
   
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|y_i)
  1. 将测试集映射到当前词典
def map2vocab(self,testdata):
    self.testset=np.zeros([1,self.vocablen])
    for word in testdata:
        self.testset[0,self.vocabulary.index(word)]+=1
  1. 预测分类结果,输出预测的分类类别
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|y_i) P(y_i)
        #
变量tdm,计算最大分类值
       
temp=np.sum(testset*tdm_vect*self.Pcates[keyclass])
        if temp>predvalue:
            predvalue=temp
            predclass=keyclass
    return predclass
  1. 算法还可以进行一些改进,将步骤e中的函数替换掉,普通的词频向量改为使用TF-IDF策略,使之有能力修正多种偏差,下面函数以TF-IDF方式生成向量空间
  2. 评估分类结果,执行我们创建的朴素贝叶斯类,获取执行结果
j.   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)#矩阵与向量的点乘 TFxIDF
l.   import numpy as np
from numpy import *
from Nbayes_pre 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))

 工程代码

不知道为什么显示不了数学公式了非常尴尬,原文链接

原文地址:https://www.cnblogs.com/kevinzhaozl/p/6625928.html