其他分享
首页 > 其他分享> > 朴素贝叶斯

朴素贝叶斯

作者:互联网

一、贝叶斯定理

1、简介

         贝叶斯理论是以18世纪的一位神学家托马斯贝叶斯(Thomas Bayes)命名。通常,事件A在事件B(发生)的条件下的概率,与事件B在事件A(发生)的条件下的概率是不一样的;然而,这两者是有确定的关系的,贝叶斯定理就是这种关系的陈述。

2、优缺点

        优点:在数据较少时仍有效,可处理多类别问题

        缺点:对输入数据准备方式较敏感。

 假设现在我们有一个数据集,它由两类数据组成,数据分布如下图所示:

         我们现在用p1(x,y)表示数据点(x,y)属于类别1(图中圆点表示的类别)的概率,用p2(x,y)表示数据点(x,y)属于类别2(图中三角形表示的类别)的概率,那么对于一个新数据点(x,y),可以用下面的规则来判断它的类别:

        如果p1(x,y) > p2(x,y),那么类别为1
        如果p1(x,y) < p2(x,y),那么类别为2


        也就是说,我们会选择高概率对应的类别。这就是贝叶斯决策理论的核心思想,即选择具有最高概率的决策。

        适用决策树不会非常成功,和简单的概率计算相比,KNN计算量太大,因此对于上述问题,最佳选择是概率比较方法。

        接下来,为了学习如何计算p1和p2概率,我们有必要讨论一下条件概率。

二、概率公式

1、条件概率

        条件概率是指事件A在事件B发生的条件下发生的概率。条件概率表示为:P(A|B),读作“A在B发生的条件下发生的概率”。若只有两个事件A,B,那么,

2、全概率公式

        若事件A1,A2,…构成一个完备事件组且都有正概率,则对任意一个事件B,有如下公式成立:

P(B)=P(BA1)+P(BA2)+...+P(BAn)=P(B|A1)P(A1) + P(B|A2)P(A2) + ... + P(B|An)P(An).

此公式即为全概率公式。

特别地,对于任意两随机事件A和B,有如下成立:

 

三、朴素贝叶斯

1、公式推导

通过条件概率公式变形得出公式:

我们把P(A)称为”先验概率”,即在B事件发生之前,我们对A事件概率的一个判断。

P(A|B)称为”后验概率”,即在B事件发生之后,我们对A事件概率的重新评估。

P(B|A)/P(B)称为”可能性函数”,这是一个调整因子,使得预估概率更接近真实概率。

先验概率是指根据以往经验和分析得到的概率,例如全概率公式 ,它往往作为“由因求果”问题中的“因”出现。后验概率是指在得到“结果”的信息后重新修正的概率,是“执果寻因”问题中的“因” 。后验概率是基于新的信息,来修正原来的先验概率后所获得的更接近实际情况的概率估计                

所以,条件概率可以理解成下面的式子:

后验概率=先验概率∗调整因子后验概率=先验概率∗调整因子
这就是贝叶斯推断的含义:我们先预估一个”先验概率”,然后加入实验结果,看这个实验到底是增强还是削弱了”先验概率”,由此得到更接近事实的”后验概率”。

如果”可能性函数”P(B|A)/P(B)>1,意味着”先验概率”被增强,事件A的发生的可能性变大;

如果”可能性函数”=1,意味着B事件无助于判断事件A的可能性;

如果”可能性函数”<1,意味着”先验概率”被削弱,事件A的可能性变小。

                                       

四、代码实现(垃圾邮件过滤)

1 流程说明
朴素贝叶斯分类器模型的训练:首先提供两组已经识别好的邮件,一组是正常邮件,另一组是垃圾邮件,然后用这两组邮件对过滤器进行“训练”。首先解析所有邮件,提取每一个词,然后计算每个词语在正常邮件和垃圾邮件中出现的概率。例如,我们假定“cute”这个词在词数(不重复)为4000的垃圾邮件中出现200次,那么该词在垃圾邮件中出现的频率就是5%;而在词数(不重复)为4000的正常邮件中出现1000次,那么该词在正常邮件中出现的频率就是25%。此时就已经初步建立了关于“cute”这个词的过滤模型。
使用朴素贝叶斯分类器模型进行过滤测试:读入一封未进行分类的新邮件,然后该邮件进行解析,发现其中包含了“cute”这个词,用P(W|S)和P(W|H)分别表示这个词在垃圾邮件和正常邮件中出现的概率。随后将邮件中解析出来的每个词(已建立对应的训练模型)属于正常邮件和垃圾邮件的概率分别进行累乘,最后比较该邮件属于正常邮件和垃圾邮件的概率大小,可将该邮件归类为概率较大的那一类。

2、构建词向量

我们把文本看成单词向量或者词条向量,也就是说将句子转换为向量。考虑出现在所有文档中的所有单词,再决定将哪些词纳入词汇表或者说所要的词汇集合,然后必须要将每一篇文档转换为词汇表上的向量。

# 创建实验样本
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]
    return postingList,classVec

def createVocabList(dataset):
    vocabSet = set([])
    for document in dataset:
        # 取并集
        vocabSet = vocabSet | set(document)
    return list(vocabSet)

# 将数据集转为词向量
def setOfWords2Vec(vocabList, inputSet):
    # 创建一个其中所含元素都为0的列表
    returnVec = [0]*len(vocabList)
    for word in inputSet:
        if word in vocabList:
            returnVec[vocabList.index(word)] = 1
        else:
            print('the word: %s is not in my Vocabulary!' % word)
    return returnVec
if __name__ == '__main__':
    postingList, classVec = loadDataSet()
    myVocabList = createVocabList(postingList)
    print('myVocabList:\n', myVocabList)
    print(setOfWords2Vec(myVocabList, postingList[0]))

 3、词向量计算概率

记w表示一个向量(可理解为经过向量化后的一封邮件),它由多个数值组成。在该例中数值个数与词汇表中的词条个数相同,则贝叶斯公式可表示为:

                                                      

 

def trainNBO(trainMatrix,trainCategory):
    #文档数目(6)
    numTrainDocs = len(trainMatrix) 
    #词数
    numWords = len(trainMatrix[0])
    ##初始化概率     
    pAbusive = sum(trainCategory) / float(numTrainDocs)
    #使用zeros()初始化后的数组如果其中一个概率值为0则最后的结果也为0,因此使用ones() 
    # numpy中的ndarray对象用于存放同类型元素的多维数组。
    p0Num = np.ones(numWords)
    p1Num = np.ones(numWords)
    p0Denom = 2.0
    p1Denom = 2.0
    for i in range(numTrainDocs):
        if trainCategory[i] == 1:
            #向量相加
            p1Num += trainMatrix[i]
            p1Denom += sum(trainMatrix[i])  
        else:
            p0Num += trainMatrix[i]
            p0Denom += sum(trainMatrix[i])
    # 分别计算某个词条在某个类别(该类别中所有词条的总数)中的占比  
   
    p1Vect = np.log(p1Num/p1Denom)
    p0Vect = np.log(p0Num/p0Denom)
    return p0Vect,p1Vect,pAbusive
if __name__ == '__main__':
    postingList, classVec = loadDataSet()
    myVocabList = createVocabList(postingList)
    trainMat = []
    for postinDoc in postingList:
        trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
    p0Vect, p1Vect, pAbusive = trainNBO(trainMat, classVec)
    print('p0Vect:\n', p0Vect)
    print('p1Vect:\n', p1Vect)
    print('文档属于侮辱性文档的概率:', pAbusive)

4、朴素贝叶斯分类函数

def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
    p1 = sum(vec2Classify * p1Vec) + np.log(pClass1)
    p0 = sum(vec2Classify * p0Vec) + np.log(1.0 - pClass1)
    if p1 > p0:
        return 1
    else:
        return 0
if __name__ == '__main__':
    postingList, classVec = loadDataSet()
    myVocabList = createVocabList(postingList)
    trainMat = []
    for postinDoc in postingList:
        trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
    p0V,p1V,pAb = trainNBO(np.array(trainMat),np.array(classVec))
    testEntry = ['love', 'my', 'dalmation']                                    
    thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
    if classifyNB(thisDoc,p0V,p1V,pAb):
         print(testEntry,'属于侮辱类')
    else:
         print(testEntry,'属于非侮辱类')                                          
    testEntry = ['stupid', 'love', 'cute']                                    
    thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))                
    if classifyNB(thisDoc,p0V,p1V,pAb):
        print(testEntry,'属于侮辱类')
    else:
        print(testEntry,'属于非侮辱类')

 在这里插入图片描述

 5、使用朴素贝叶斯进行交叉验证

def bagOfWords2Vec(vocabList,inputSet):
    returnVec = [0] * len(vocabList)
    for word in inputSet:
        if word in vocabList:
            returnVec[vocabList.index(word)] += 1
    return returnVec

def textParse(bigString):
    #将非数字、单词外的任意字符串作为切分标志
    listOfTokens = re.split('\\W*',bigString)       
    #为了使所有词的形式统一,除了单个字母,例如大写的I,其余的单词变成小写
    return [tok.lower() for tok in listOfTokens if len(tok) > 2]

def spamTest():
    docList = [];classList = [];fullTest = []
    #导入并解析50个文件,并记录对应的标签值,垃圾邮件标记为1
    for i in range(1,26):
        wordList = textParse(open('C:/Users/cool/Desktop/mach/email/spam/%d.txt'% i,'r').read())
        docList.append(wordList)
        fullTest.append(wordList)
        classList.append(1)
        wordList = textParse(open('C:/Users/cool/Desktop/mach/email/ham/%d.txt'% i,'r').read())
        docList.append(wordList)
        fullTest.append(wordList)
        classList.append(0)
    #获得50个文件构成的词列表
    vocabList = createVocabList(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])
    trainMat = [];trainClass = []
    #构建训练集词向量列表,训练集标签
    for docIndex in trainingSet:
        trainMat.append(setOfWords2Vec(vocabList,docList[docIndex]))
        trainClass.append(classList[docIndex])
    #训练算法,计算分类所需的概率
    p0V,p1V,pSpam = trainNBO(np.array(trainMat),np.array(trainClass))
    #分类错误个数初始化为0
    errorCount = 0
    #,遍历测试集,验证算法错误率
    for docIndex in testSet:
        wordVector = setOfWords2Vec(vocabList,docList[docIndex]) 
        if classifyNB(np.array(wordVector),p0V,p1V,pSpam) != classList[docIndex]:
            errorCount += 1
    print('错误率:%.2f%%'%(float(errorCount)/len(testSet)*100))
if __name__ == '__main__':
    spamTest()

在这里插入图片描述

 

标签:__,概率,append,贝叶斯,朴素,np,邮件
来源: https://blog.csdn.net/shirakami00/article/details/121461270