Bootstrap

贝叶斯分类器以及Python实现

贝叶斯分类器

贝叶斯分类器的分类原理是通过某对象的先验概率,利用贝叶斯公式计算出其后验概率,即该对象属于某一类的概率,选择具有最大后验概率的类作为该对象所属的类。

介绍一下先验概率:是指根据以往经验和分析得到的概率,就是我们可以通过我们已经得到的训练集得到的概率
后验概率:就是我们要求得、要预测的概率,并且通过这种概率去估计样本的可能类别。

介绍一下贝叶斯公式 :可以看作是一种条件概率公式的推广
这里写图片描述

贝叶斯分类器 :

  1. 贝叶斯分类器的原理就是基于这个贝叶斯公式 。
    我们把x看成一个新的样本的特征,w看成样本的可能结果 (就是可能存在的类别)左边的公式的意义就是在x的条件下出现w这种情况的概率。也就是我们所说的后验概率,这个概率可以通过右边的项求得。

  2. 对于右边的式子我们可以看出 p(x) 对于所有的 w 来说是一个常数,我们需要关心的就是分子上的两项的大小(就是利用先验概率对分子作出一个合理的估计)

  3. 下面介绍一下对分子的估计的方法 :
    • 对于p(w) 是容易估计的,根据大数定理我们可以从我们的训练样本中根据w出现的频率去估计这个概率。
    • 而对于后面的那一项类条件概率(也叫似然)我们采用极大似然法进行估计
    • 先介绍一下极大似然原理 : 就是说出现一组x的值的时候我们总是认为,实验条件有利于x的产生,这样的话我门假设一个模型(假设一组参数),因为有利于x的产生,我们只需要求出在 x 的前提下取得最大值时候的 参数值即可。就相当于 x 是常数求出参数使得这个模型取到最大值。
    • 什么叫做极大似然法呢 ?其实我觉得这个就是一种把对概率的估计转化成一种对于参数的估计 (其实在机器学习的学习过程就是一种对参数的估计过程)就是假设这个似然 (条件概率)符合一种我们常见的分布我们就可以把这种分布假设出来,然后利用已知的数据对我们假设的模型参数进行一个估计。这就是极大似然法,一般而言对于连续的变量我们可以用正态分布(关于为什么可以看成正态分布 中心极限定理有过证明)的模型进行估计(有的时候也可以先取对数在用正态估计 在估计之前可以先将数据可视化再对模型参数进行选择)对于离散的我们一般直接算概率值当作频率
    • 最后只需要选择一个概率最大的当作类输出就可以了
      这是对于一个特征的贝叶斯分类器,下面介绍一种朴素的贝叶斯分类器

朴素贝叶斯分类器

朴素贝叶斯分类器与贝叶斯分类器的原理一致,但是朴素贝叶斯公式有两个默认的前提条件 :
1. 各个特征之间相互独立
2. 各个特征同等重要

认为每个特征之间不存在依赖关系根据相互独立事件的概率公式可以得到朴素的贝叶斯公式

这里写图片描述

由于p(yi) 的概率都是一样的所以我们关心的还是右边的概率的大小,估计的方法与上面的一致,就是用最大似然法进行估计。

贝叶斯分类器的拉普拉斯修正

首先先介绍一下为什么需要拉普拉斯修正,因为我们的样本集有限,对于某些离散的值可能并没有出现,这样的话会导致乘积的概率为0,严重影响了我们最终的分类结果,显然不是我门想要的结果,这样就出现了拉普拉斯修正方法。

拉普拉斯修正方法 : 就是对于一个离散的值我们在使用的时候不是直接输出它的概率,而是对概率值进行“平滑” 处理。即默认所有的特征都出现过一次,将概率改成下面的形式 其中 N 是全体特征的总数。

这里写图片描述

这里写图片描述

D是指的这一类的总数目。
这样就避免了概率值为0的情况。

贝叶斯分类需要注意的另外一种情况 :

由于贝叶斯分布需要对很多个很小的数作乘法,所以可能会出现下溢的情况,所以我们在进行处理的时候可以对概率的乘积取自然对数,根据自然对数函数的单调性,不会改变最终的大小关系,但是很好的防止了下溢出的问题。

朴素贝叶斯的实现代码 :

import numpy as np 
import math
# 使用词集法进行贝叶斯分类
# 构造数据集,分类是侮辱性 or 非侮辱性
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']]
    classVec = [0,1,0,1,0,1]    #1 is abusive, 0 not
    return postingList, classVec


# 创建一个包涵所有词汇的列表 , 为后面建立词条向量使用
def createlist (dataset) :
    vovabset = set ([])
    for vec in dataset :
        vovabset = vovabset | set (vec)
    return list (vovabset)

# 将词条转化为向量的形式
def changeword2vec (inputdata, wordlist) :
    returnVec = [0] * len (wordlist)
    for word in inputdata :
        if word in wordlist :
            returnVec[wordlist.index(word)] = 1
    return returnVec

# 创建贝叶斯分类器 
def trainNBO (dataset, classlebels) :
    num_of_sample = len (dataset)
    num_of_feature = len (dataset[0])
    pAusuive = sum (classlebels) / num_of_sample # 侮辱性语言的概率
    p0Num = np.ones (num_of_feature)
    p1Num = np.ones (num_of_feature)
    p0tot = num_of_feature
    p1tot = num_of_feature
    for i in range (num_of_sample) :
        if classlebels[i] == 1 :
            p1Num += dataset[i]
            p1tot += sum (dataset[i])
        else :
            p0Num += dataset[i]
            p0tot += sum (dataset[i])   
    p0Vec = p0Num / p0tot
    p1Vec = p1Num / p1tot
    for i in range (num_of_feature) :
        p0Vec[i] = math.log (p0Vec[i])
        p1Vec[i] = math.log (p1Vec[i])
    return p0Vec, p1Vec, pAusuive


#  定义分类器 
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
    p1 = sum(vec2Classify * p1Vec) + log(pClass1)    #element-wise mult
    p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)
    if p1 > p0:
        return 1
    else: 
        return 0

# 测试代码 
dataset,classlebels = loadDataset ()
wordlist = createlist (dataset)
print (wordlist)
print (changeword2vec (dataset[0], wordlist))
trainmat = []
for temp in dataset :
    trainmat.append (changeword2vec (temp,wordlist))
p0V, p1V, pAb = trainNBO (trainmat, classlebels)
print (p0V)
print (p1V)
print (pAb)
;