机器学习 朴素贝叶斯(NaiveBayes)

朴素贝叶斯(Naive Bayes)

算法思想

   朴素贝叶斯(Naive Bayes)是基于贝叶斯定理与特征条件假设的分类方法。给定一个未知的样本 X X X,分类法将预测 X X X属于具有最高后验概率的类,即,未知的样本分配给 y j y_j yj,当且仅当
P ( y j ∣ X ) > P ( y j ∣ X ) , 1 ≤ i ≤ k , i ≠ j P(y_j|X)>P(y_j|X),1≤i≤k,i \neq j P(yjX)>P(yjX),1ik,i̸=j

贝叶斯定理

   介绍贝叶斯定理前,先理解条件概率和全概率公式。
先验概率
   P ( X = 玩 l o l ) = 0.6 ; P ( X = 不 玩 l o l ) = 0.4 P(X=玩lol)=0.6;P(X=不玩lol)=0.4 P(X=lol)=0.6P(X=lol)=0.4,这个概率是统计得到的,即X的概率分布已知,我们称其为先验概率(prior probability);

后验概率
P(Y=男性|X=玩lol)=0.8,P(Y=小姐姐|X=玩lol)=0.2
P(Y=男性|X=不玩lol)=0.2,P(Y=小姐姐|X=不玩lol)=0.8
   那么我想问在已知玩家为男性的情况下,他是lol玩家的概率是多少,最后算出的P(X=玩lol|Y=男性)称之为X的后验概率,它获得是在观察到事件Y发生后得到的。

条件概率
   P ( A ∣ B ) P(A|B) P(AB)表示事件 B B B已经发生的前提下,事件 A A A发生的概率,叫做事件 B B B发生下事件 A A A的条件概率。其基本求解公式为
P ( A ∣ B ) = P ( A B ) P ( B ) P(A|B)=\frac{P(AB)}{P(B)} P(AB)=P(B)P(AB)
全概率公式
  若时间 B 1 , B 2 , . . . B n B_1,B_2,...B_n B1,B2,...Bn构成完备事件组,且 P ( B i ) > 0 ( i = 1 , 2 , 3 , . . . , n ) P(B_i)>0(i=1,2,3,...,n) P(Bi)>0(i=1,2,3,...,n),则有对于任何事件A,有
P ( A ) = ∑ i = 1 n P ( B i ) P ( A ∣ B i ) P(A)=\sum_{i=1}^{n}P(B_i)P(A|B_i) P(A)=i=1nP(Bi)P(ABi)

贝叶斯定理
  若事件 B 1 , B 2 , . . . B n B_1,B_2,...B_n B1,B2,...Bn构成完备事件组,且 P ( B i ) > 0 ( i = 1 , 2 , 3 , . . . , n ) P(B_i)>0(i=1,2,3,...,n) P(Bi)>0(i=1,2,3,...,n),则有对于任何概率大于零事件A,有
P ( B i ∣ A ) = P ( A B i ) P ( A ) = P ( B i ) P ( A ∣ B i ) P ( A ) P(B_i|A)=\frac{P(AB_i)}{P(A)}=\frac{P(B_i)P(A|B_i)}{P(A)} P(BiA)=P(A)P(ABi)=P(A)P(Bi)P(ABi)
再根据全概率公式,有
P ( B i ∣ A ) = P ( B i ) P ( A ∣ B i ) ∑ i = 1 n P ( B i ) P ( A ∣ B i ) P(B_i|A)=\frac{P(B_i)P(A|B_i)}{\sum_{i=1}^{n}P(B_i)P(A|B_i)} P(BiA)=i=1nP(Bi)P(ABi)P(Bi)P(ABi)

模型推导

  给定训练数据集 ( X , Y ) (X,Y) (X,Y),其中每个样本 X X X都包括 n n n维特征,即 x = ( x 1 , x 2 , ⋅ ⋅ ⋅ , x n ) x=(x_1,x_2,⋅⋅⋅,x_n) x=(x1,x2,,xn),类标记集合含有K种类别,即 y = ( y 1 , y 2 , ⋅ ⋅ ⋅ , y k ) y=(y_1,y_2,⋅⋅⋅,y_k) y=(y1,y2,,yk),如果现在来了一个新样本x我们要怎么判断它的类别?从概率的角度来看,这个问题就是给定x,它属于哪个类别的概率更大。那么问题就转化为求 P ( y 1 ∣ x ) P(y_1|x) P(y1x), P ( y 2 ∣ x ) P(y_2|x) P(y2x), P ( y k ∣ x ) P(y_k|x) P(ykx)中最大的那个,那 P ( y k ∣ x ) P(y_k|x) P(ykx)怎么求解?答案就是贝叶斯定理:
P ( y i ∣ X ) = P ( y i ) P ( X ∣ y i ) P ( X ) P(y_i|X)=\frac{P(y_i)P(X|y_i)}{P(X)} P(yiX)=P(X)P(yi)P(Xyi)
  目标函数:
m a x P ( y i ∣ X ) max P(y_i|X) maxP(yiX)
朴素贝叶斯分类器所需要的信息

  • 计算每个类的先验概率 P ( y i ) P(y_i) P(yi)
    P ( y i ) = n j n P(y_i)=\frac{n_j}{n} P(yi)=nnj
    其中, n j n_j nj y i y_i yi类的训练样本数,而 n n n是训练样本总数

  • 计算 P ( X ∣ y i ) P(X|y_i) P(Xyi)
      计算 P ( X ∣ y i ) P(X|y_i) P(Xyi)需要得到联合改了分布: P ( X 1 ∣ , X 2 , X 3 , . . . , X 4 ∣ Y ) P(X_1|,X_2,X_3,...,X_4|Y) P(X1,X2,X3,...,X4Y),但是它的参数规模是指数数量级别的,假设第 i i i维特征 x i x_i xi可取值的个数有 S i S_i Si个,类别取值个数为k个,那么参数个数为 k ∏ n j = 1 S j k∏_n^{j=1}S_j knj=1Sj
      这显然是不可行的。针对这个问题,朴素贝叶斯算法对条件概率分布做了独立性的假设,通俗地讲就是说假设各个维度的特征 x 1 , x 2 , ⋅ ⋅ ⋅ , x n x_1,x_2,⋅⋅⋅,x_n x1,x2,,xn互相独立,由于这是一个较强的假设,朴素贝叶斯算法也因此得名。在这个假设的前提上,条件概率可以转化为:
    P ( X ∣ y i ) = P ( ( x 1 , x 2 , x 3 , . . . , x n ∣ y i ) = P ( x 1 ∣ y j ) P ( x 2 ∣ y j ) . . . P ( x n ∣ y j ) P(X|y_i)=P((x_1,x_2,x_3,...,x_n|y_i)=P(x_1|y_j)P(x_2|y_j)...P(x_n|y_j) P(Xyi)=P((x1,x2,x3,...,xnyi)=P(x1yj)P(x2yj)...P(xnyj)

  • 计算 P ( x i ∣ y i ) P(x_i|y_i) P(xiyi)
    1.若第 i i i个属性 A i A_i Ai是离散值属性,则
    P ( x i ∣ y i ) = n i j n j P(x_i|y_i)=\frac{n_{ij}}{n_j} P(xiyi)=njnij

    其中 n i j n_ij nij是属性 A i A_i Ai上具有值 x i x_i xi y j y_j yj类的训练样本数,而 n j n_j nj y j y_j yj类的训练样本数

2.若第 i i i个属性 A i A_i Ai是连续值属性

  • A j A_j Aj离散化
  • 假定 A j A_j Aj服从高斯分布
    在这里插入图片描述
    其中, μ i j μ_{ij} μij, σ i j σ_{ij} σij分别为给定yj类的训练样本在属性Ai上的均值和标准差

实例演算
在这里插入图片描述
解答过程:
在这里插入图片描述

Laplace估计

  在实际应用中,会出现一个问题如果诸条件概率 P ( X i = x i ∣ Y = y j ) P(X_i=x_i |Y=y_j) P(Xi=xiY=yj) 中的一个为0,则它们的乘积(计算P(X |Y=yj)的表达式)为0,很可能每个P(X |Y=y_j)都为0。
  为此朴素贝叶斯模型计算 P ( X ∣ y i ) P(X|y_i) P(Xyi)时引入Laplace估计,以避免这种情况的出现。
原 估 计 : P ( X i = x i ∣ Y = y j ) = n i j n j 原估计: P(X_i=x_i |Y=y_j) = \frac{n_{ij}}{n_j} :P(Xi=xiY=yj)=njnij
L a p l a c e 估 计 : P ( X i = x i ∣ Y = y j ) = n i j + 1 n j + k Laplace估计: P(X_i=x_i |Y=y_j) = \frac{n_{ij}+1}{n_j+k} Laplace:P(Xi=xiY=yj)=nj+knij+1

算法特点

  • 对孤立的噪声点的鲁棒性
    个别点对概率估计的影响很小
  • 容易处理缺失值
    在估计概率时忽略缺失值的训练实例
  • 对不相关属性的鲁棒性
    各类在不相关属性上具有类似分布
  • 类条件独立假设可能不成立
    使用其他技术,如贝叶斯信念网络( Bayesian Belief Networks,BBN)

python实现

from numpy import *
class Naive_Bayes:
    def __init__(self):
        self._creteria = "NB"
    #创建不重复词集
    def _creatVocabList(self,dataSet):
        vocabSet = set([])  # 创建一个空的SET
        for document in dataSet:
            vocabSet = vocabSet | set(document)  # 并集
        return list(vocabSet)  # 返回不重复词表(SET的特性)
    #文档词集向量模型
    def _setOfWordToVec(self,vocabList, inputSet):
        """
        功能:给定一行词向量inputSet,将其映射至词库向量vocabList,出现则标记为1,否则标记为0.
        """
        returnVec = [0] * len(vocabList)
        for word in inputSet:
            if word in vocabList:
                returnVec[vocabList.index(word)] = 1
        return returnVec
    #文档词袋模型
    def _bagOfsetOfWordToVec(self,vocabList, inputSet):
        """
        功能:对每行词使用第二种统计策略,统计单个词的个数,然后映射到此库中
        输出:一个n维向量,n为词库的长度,每个取值为单词出现的次数
        """
        returnVec = [0] * len(vocabList)
        for word in inputSet:
            if word in vocabList:
                returnVec[vocabList.index(word)] += 1 #更新此处代码
        return returnVec
    def _trainNB0(self,trainMatrix, trainCategory):
        """
        输入:训练词矩阵trainMatrix与类别标签trainCategory,格式为Numpy矩阵格式
        功能:计算条件概率p0Vect、p1Vect和类标签概率pAbusive
        """
        numTrainDocs = len(trainMatrix)#样本个数
        numWords = len(trainMatrix[0])#特征个数,此处为词库长度
        pAbusive = sum(trainCategory) / float(numTrainDocs)#计算负样本出现概率(先验概率)
        p0Num = ones(numWords)#初始词的出现次数为1,以防条件概率为0,影响结果
        p1Num = ones(numWords)#同上
        p0Denom = 2.0#类标记为2,使用拉普拉斯平滑法,
        p1Denom = 2.0
        #按类标记进行聚合各个词向量
        for i in range(numTrainDocs):
            if trainCategory[i] == 0:
                p0Num += trainMatrix[i]
                p0Denom += sum(trainMatrix[i])
            else:
                p1Num += trainMatrix[i]
                p1Denom += sum(trainMatrix[i])
        p1Vect = log(p1Num / p1Denom)#计算给定类标记下,词库中出现某个单词的概率
        p0Vect = log(p0Num / p0Denom)#取log对数,防止条件概率乘积过小而发生下溢
        return p0Vect, p1Vect, pAbusive
    def _classifyNB(self,vec2Classify, p0Vec, p1Vec, pClass1):
        """
        该算法包含四个输入:
        vec2Classify表示待分类的样本在词库中的映射集合,
        p0Vec表示条件概率P(wi|c=0)P(wi|c=0),
        p1Vec表示条件概率P(wi|c=1)P(wi|c=1),
        pClass1表示类标签为1时的概率P(c=1)P(c=1)。
        p1=ln[p(w1|c=1)p(w2|c=1)…p(wn|c=1)p(c=1)]
        p0=ln[p(w1|c=0)p(w2|c=0)…p(wn|c=0)p(c=0)]
        log取对数为防止向下溢出
        功能:使用朴素贝叶斯进行分类,返回结果为0/1
        """
        p1 = sum(vec2Classify * p1Vec) + log(pClass1)
        p0 = sum(vec2Classify * p0Vec) + log(1 - pClass1)
        if p1 > p0:
            return 1
        else:
            return 0
    #test
    def testingNB(self,testSample):
        "step1:加载数据集与类标号"
        listOPosts, listClasses = loadDataSet()
        "step2:创建词库"
        vocabList = self._creatVocabList(listOPosts)
        "step3:计算每个样本在词库中出现的情况"
        trainMat = []
        for postinDoc in listOPosts:
            trainMat.append(self._bagOfsetOfWordToVec(vocabList, postinDoc))
        p0V, p1V, pAb = self._trainNB0(trainMat, listClasses)
        "step4:测试"
        thisDoc = array(self._bagOfsetOfWordToVec(vocabList, testSample))
        result=self._classifyNB(thisDoc, p0V, p1V, pAb)
        print (testSample, 'classified as:', result)
        # return result
###
# 加载数据集
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
#测试
if __name__=="__main__":
    clf = Naive_Bayes()
    testEntry = [['love', 'my', 'girl', 'friend'],
                 ['stupid', 'garbage'],
                 ['Haha', 'I', 'really', "Love", "You"],
                 ['This', 'is', "my", "dog"],
                 ['maybe','stupid','worthless']]
    for item in testEntry:
        clf.testingNB(item)

程序结果:
在这里插入图片描述

使用朴素贝叶斯分类器对垃圾邮件进行过滤:

import re
from numpy import *
def textParse(bigString):
    import re
    listOfTokens=re.split(r'\w*',bigString)
    return [tok.lower() for tok in listOfTokens if len(tok)>2]
def spamTest():
    clf = Naive_Bayes()
    docList=[]
    classList=[]
    fullText=[]
    for i in range(1,26):
        wordList=textParse(open('email/spam/%d.txt'%i,encoding='ISO-8859-1').read())
        docList.append(wordList)
        fullText.extend(wordList)
        classList.append(1)
        wordList=textParse(open('email/ham/%i.txt'%i,encoding='ISO-8859-1').read())
        docList.append(wordList)
        fullText.extend(wordList)
        classList.append(0)
    print(docList)
    vocabList=clf._creatVocabList(docList)
    trainingSet = list(range(50));testSet=[]
    for i in range(10):
        randIndex=int(random.uniform(0,len(trainingSet)))
        testSet.append(trainingSet[randIndex])
        del (trainingSet[randIndex])
    trainMatix=[];trainClasses=[]
    for docIndex in trainingSet:
        trainMatix.append(clf._bagOfsetOfWordToVec(vocabList,docList[docIndex]))
        trainClasses.append(classList[docIndex])
    p0V,p1V,pSpam=clf._trainNB0(array(trainMatix),array(trainClasses))
    errorCount = 0
    for docIndex in testSet:
        wordVector = clf._bagOfsetOfWordToVec(vocabList,docList[docIndex])
        if clf._classifyNB(array(wordVector), p0V, p1V, pSpam)!=classList[docIndex]:
            errorCount+=1
            print ("classification error",docList[docIndex],classList[docIndex])
    print ('the error rate is :',float(errorCount)/len(testSet))
    
if __name__=="__main__":    
    spamTest()
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值