机器学习——贝叶斯算法

一. 简介

  贝叶斯定理是18世纪英国数学家托马斯·贝叶斯(Thomas Bayes)提出得重要概率论理论。在该定理提出之前,人们已经能够计算“正向概率”,如“假设袋子里面有 N 个白球,M 个黑球,你伸手进去摸一把,摸出黑球的概率是多大”。而一个自然而然的问题是反过来:“如果我们事先并不知道袋子里面黑白球的比例,而是闭着眼睛摸出一个(或好几个)球,观察这些取出来的球的颜色之后,那么我们可以就此对袋子里面的黑白球的比例作出什么样的推测”。这个问题,就是所谓的逆向概率问题。

二. 定理

条件概率(后验概率):就是事件A在另一个事件B已经发生的条件下发生概率,公式表示为P(A|B),读作“在B条件下A的概率”。

公式:P(A|B)=\frac{P(AB)}{P(B)}

2 联合概率:表示两件事情共同发生的概率,A与B的联合概率表示为P(A,B)。

边缘概率(又称先验概率): 

  边缘概率是指某个事件发生的概率,而与其它事件无关,它是由联合概率边缘化得到的,即在联合概率中,把最终结果不需要的事件合并成事件全概率而消失。例如P(A,B1)表示事件A与事件B1同时发生的概率,P(A,B2)表示事件A与事件B2同时发生的概率,若事件B1与B2合在一起为B事件发生的全部情况,则A 的边缘概率P(A)=p(A,B1)+P(A,B2)。

贝叶利公式:

P(A|B)=\frac{P(B|A)*P(A)}{P(B)}

  • 其中P(A|B)是在 B 发生的情况下 A 发生的可能性。
  1. P(A)是 A 的先验概率,之所以称为“先验”是因为它不考虑任何 B 方面的因素。

  2. P(A|B)是已知 B 发生后 A 的条件概率,也由于得自 B 的取值而被称作 A 的后验概率。

  3. P(B|A)是已知 A 发生后 B 的条件概率,也由于得自 A 的取值而被称作 B 的后验概率。

  4. P(B)是 B 的先验概率,也作标淮化常量(normalizing constant)。

    所以贝叶斯公式可以表示为:后验概率=先验概率 * 调整因子

    如果调整因子>1,则表示先验概率被增强,事件A发生的可能性变大。

    如果调整因子=1,则表示事件B对判断事件A发生的概率没有帮助。

    如果调整因子<1,则表示先验概率被削弱,事件A发生的可能性变小。

三. 贝叶斯算法流程

贝叶斯算法的工作流程如下:

  1. 定义模型:选择合适的概率分布来描述模型参数和观测数据之间的关系,通常使用参数化的概率模型。
  2. 设定先验概率:选择适当的先验分布,反映我们对模型参数的初始信念。
  3. 收集数据:获取观测数据集 。
  4. 计算后验概率:使用贝叶斯定理结合观测数据和先验概率来计算参数的后验概率分布:
  5. 进行推断:基于后验概率进行模型参数的估计、预测、分类等任务。
  6. 更新模型:随着新数据的积累,可以周期性地重复上述过程,不断更新后验概率和模型参数。

四. 实例:垃圾邮件过滤

1 邮件数据读取

import numpy as np  # 导入NumPy库,用于数值计算
import re  # 导入re库,用于正则表达式操作
import random  # 导入random库,用于生成随机数
 
# 定义一个函数textParse,用于处理文本数据
def textParse(input_string):
    listofTokens = re.split(r'\W+', input_string)  # 使用正则表达式切分输入的字符串
    return [tok.lower() for tok in listofTokens if len(listofTokens) > 2]  # 返回切分后的单词列表,转换为小写并去除长度小于等于2的单词
 
# 定义一个函数spam,用于处理垃圾邮件数据
def spam():
    doclist = []  # 创建一个空列表,用于存储文档数据
    classlist = []  # 创建一个空列表,用于存储类别信息
    for i in range(1, 26):  # 循环处理1到25号文档
        # 处理垃圾邮件文档
        wordlist = textParse(open('email/spam/%d.txt' % i, 'r').read())  # 读取并处理垃圾邮件文档
        doclist.append(wordlist)  # 将处理后的单词列表添加到文档列表
        classlist.append(1)  # 将类别标签1(表示垃圾邮件)添加到类别列表
        
        # 处理非垃圾邮件文档
        wordlist = textParse(open('email/ham/%d.txt' % i, 'r').read())  # 读取并处理非垃圾邮件文档
        doclist.append(wordlist)  # 将处理后的单词列表添加到文档列表
        classlist.append(0)  # 将类别标签0(表示非垃圾邮件)添加到类别列表
        
        ......

定义主函数spam执行以下步骤:

  1. 创建两个空列表doclist和classlist,用于分别存储文档数据和类别信息。
  2. 使用一个循环,依次处理垃圾邮件和非垃圾邮件文档,文档编号从1到25。
  3. 对于每个文档,使用textParse函数读取并处理文档内容,将处理后的单词列表添加到doclist中。
  4. 对于垃圾邮件文档,将类别标签1(表示垃圾邮件)添加到classlist中;对于非垃圾邮件文档,将类别标签0(表示非垃圾邮件)添加到classlist中。

2 预料表与特征向量构建

# 定义一个函数,用于创建词汇表
def creatVocablist(doclist):
    vocabSet = set([])  # 创建一个空集合,用于存储所有文档中出现的不重复单词
    for document in doclist:  # 遍历文档列表中的每个文档
        vocabSet = vocabSet | set(document)  # 将文档中的单词添加到词汇表集合中(去重)
    return list(vocabSet)  # 将词汇表集合转换为列表并返回
 
# 定义一个函数,将文本数据转换为词向量
def setOfWord2Vec(vocablist, inputSet):
    returnVec = [0] * len(vocablist)  # 创建一个与词汇表长度相同的零向量
    for word in inputSet:  # 遍历输入的单词列表
        if word in vocablist:  # 如果单词在词汇表中出现
            returnVec[vocablist.index(word)] = 1  # 将词向量中对应位置的值设为1
    return returnVec  # 返回生成的词向量
 
# 定义主函数spam,处理垃圾邮件数据
def spam():
    # ...
    
    vocablist = creatVocablist(doclist)  # 创建词汇表
    trainSet = list(range(50))  # 创建训练集索引列表,初始包含前50个文档的索引
    testSet = []  # 创建测试集索引列表,初始为空
    for i in range(10):  # 从训练集中随机选择10个样本作为测试集
        randIndex = int(random.uniform(0, len(trainSet)))  # 随机选择一个索引
        testSet.append(trainSet[randIndex])  # 将选择的索引添加到测试集
        del(trainSet[randIndex])  # 在训练集中删除已选择的索引
    trainMat = []  # 创建训练矩阵,用于存储训练数据的词向量
    trainClass = []  # 创建训练类别标签列表,用于存储训练数据的类别
    for docIndex in trainSet:  # 遍历训练集中的每个文档索引
        trainMat.append(setOfWord2Vec(vocablist, doclist[docIndex]))  # 将文档转换为词向量并添加到训练矩阵
        trainClass.append(classlist[docIndex])  # 添加文档的类别标签
    p0Vec, p1Vec, p1 = trainNB(np.array(trainMat), np.array(trainClass))  # 使用朴素贝叶斯算法进行训练
    errorCount = 0  # 初始化错误计数器
    for docIndex in testSet:  # 遍历测试集中的每个文档索引
        wordVec = setOfWord2Vec(vocablist, doclist[docIndex])  # 将测试文档转换为词向量
        if classifyNB(np.array(wordVec), p0Vec, p1Vec, p1) != classlist[docIndex]:  # 使用贝叶斯分类器进行分类
            errorCount += 1  # 如果分类错误,错误计数加1
    print('当前10个测试样本,错了:', errorCount)  # 输出错误计数

3 分类别统计词频

# 定义朴素贝叶斯分类器的训练函数
def trainNB(trainMat, trainClass):
    numTrainDocs = len(trainMat)  # 训练文档的数量
    numWords = len(trainMat[0])  # 特征向量的长度(词汇表的大小)
    p1 = sum(trainClass) / float(numTrainDocs)  # 计算类别1(垃圾邮件)的概率
 
    # 初始化类别0和类别1的计数器和分母
    p0Num = np.ones((numWords))  # 初始化类别0的计数器,进行拉普拉斯平滑处理
    p1Num = np.ones((numWords))  # 初始化类别1的计数器,进行拉普拉斯平滑处理
    p0Denom = 2  # 初始化类别0的分母,通常设置为类别个数
    p1Denom = 2  # 初始化类别1的分母,通常设置为类别个数
 
    for i in range(numTrainDocs):  # 遍历训练文档
        if trainClass[i] == 1:  # 如果文档属于垃圾邮件类别
            p1Num += trainMat[i]  # 增加类别1的计数器,统计词汇在垃圾邮件中出现的次数
            p1Denom += sum(trainMat[i])  # 增加类别1的分母,统计垃圾邮件中的总词数
        else:  # 如果文档属于非垃圾邮件类别
            p0Num += trainMat[i]  # 增加类别0的计数器,统计词汇在非垃圾邮件中出现的次数
            p0Denom += sum(trainMat[i])  # 增加类别0的分母,统计非垃圾邮件中的总词数
 
    # 计算类别0和类别1中每个词汇的条件概率
    p0Vect = np.log(p0Num / p0Denom)  # 类别0的条件概率向量
    p1Vect = np.log(p1Num / p1Denom)  # 类别1的条件概率向量
 
    return p0Vect, p1Vect, p1  # 返回条件概率向量和类别1的概率

4 贝叶斯公式对数变换 

def trainNB(trainMat,trainClass):
    ......
    p1Vec = np.log(p1Num/p1Denom)
    p0Vec = np.log(p0Num/p0Denom)
    return p0Vec,p1Vec,p1
 
 
def classifyNB(wordVec,p0Vec,p1Vec,p1_class):    
    p1 = np.log(p1_class) + sum(wordVec*p1Vec)
    p0 = np.log(1.0 - p1_class) + sum(wordVec*p0Vec)
    if p0>p1:
        return 0
    else:
        return 1

五. 总结

  贝叶斯公式的用途在于通过己知三个概率来推测第四个概率。它的内容是:在 B 出现的前提下,A 出现的概率等于 A 出现的前提下 B 出现的概率乘以 A 出现的概率再除以 B 出现的概率。通过联系 A 与 B,计算从一个事件发生的情况下另一事件发生的概率,即从结果上溯到源头(也即逆向概率)。总的来说,贝叶斯算法提供了一种基于概率的框架,可以有效地处理分类问题和概率估计问题。它的优点包括简单、易于实现,适用于各种数据类型,尤其在处理高维数据和大规模文本数据时表现出色。

  • 15
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值