机器学习:朴素贝叶斯的应用之垃圾邮件过滤

机器学习:朴素贝叶斯的应用之垃圾邮件过滤

文章目录

  • 机器学习:朴素贝叶斯的应用之垃圾邮件过滤
    • 1.相关概念
      • 1.条件概率:
      • 2.贝叶斯公式:
      • 3.拉普拉斯平滑:
    • 2.朴素贝叶斯分类器
      • 1.根据已知数据计算先验概率以及条件概率
      • 2.根据MAP分类准则与贝叶斯准则判定样例
      • 注意点:
    • 3.垃圾邮件的过滤(python实现)
        • 1.数据集介绍
        • 2.数据预处理
        • 3.构造朴素贝叶斯分类器
        • 4.测试并获得测试结果
        • 完整代码

1.相关概念

1.条件概率:

条件概率是指某一事件A发生的可能性,表示P(A)。而条件概率指的是某一事件A已经发生了条件下,另一事件B发生的可能性,表示为P(B|A)。
怎么计算条件概率呢?设A,B是两个独立事件,且P(A)>0,称P(B|A)=P(AB)/P(A)为在事件A发生的条件下,事件B发生的条件概率。P(AB)表示事件A和B同时发生的概率。

机器学习:朴素贝叶斯的应用之垃圾邮件过滤_第1张图片

例如在上述数据中,要计算在已知Play Tennis成立时Outlook是Sunny的概率,这个时候其实就是在算条件概率。

假设事件A为Play Tennis成立,事件B为Outlook是Sunny,则根据表中数据可知P(AB)=2/14,P(A)=9/14 则P(B|A)=P(AB)/P(A)=2/9

2.贝叶斯公式:

当已知引发事件发生的各种原因的概率,想要算该事件发生的概率时,我们可以用全概率公式。image-20221129112015304

但是如若现在反过来,已知事件已经发生了,但是想要计算引发该事件的各种原因的概率时,我们就需要用到贝叶斯公式。

机器学习:朴素贝叶斯的应用之垃圾邮件过滤_第2张图片

简单变换可得

机器学习:朴素贝叶斯的应用之垃圾邮件过滤_第3张图片

3.拉普拉斯平滑:

零概率:在计算事件的概率时,如果某个事件在观察样本库(训练集)中没有出现过,会导致该事件的概率结果是0。但是对于实际情况来说这是不合理的,不能因为一个事件没有观察到,就被认为该事件一定不可能发生(即该事件的概率为0)。这时就需要我们的拉普拉斯平滑(Laplacian smoothing) 。
拉普拉斯平滑指的是,假设N表示训练数据集总共有多少种类别,Ni表示训练数据集中第i总共有多少种取值。则训练过程种在算类别的概率时分子加1,分母加N,算条件概率时分子加1,分母加Ni。

2.朴素贝叶斯分类器

由贝叶斯公式可以推断朴素贝叶斯分类器是一个生成式模型(建立条件概率模型用于求解最大化后验模型)

以上述天气与是否打球数据为例,分析贝叶斯分类器的步骤

假设要求已知样例image-20221129131530824的类别

将其归类在Play Tennis=Yes或Play Tennis=No上

1.根据已知数据计算先验概率以及条件概率

机器学习:朴素贝叶斯的应用之垃圾邮件过滤_第4张图片

机器学习:朴素贝叶斯的应用之垃圾邮件过滤_第5张图片

2.根据MAP分类准则与贝叶斯准则判定样例

机器学习:朴素贝叶斯的应用之垃圾邮件过滤_第6张图片

注意点:

当遇到连续型数据时通过高斯分布计算
image-20221129132510909

训练集中属性值未出现的情况下要进行“拉普拉斯修正”
image-20221129132526188

当属性数量多的情况下,导致累乘结果下溢。采用防溢出策略(累乘变累加)

image-20221129132533381

3.垃圾邮件的过滤(python实现)

1.数据集介绍

此数据集包含训练集train与测试集test ,训练集里包含24个以txt格式存储的普通邮件文本与24个以txt格式存储的垃圾邮件文本,测试集里包含普通邮件与垃圾邮件文本各一个,结构树如下

├─ Emails

│ ├─ test

│ │ ├─ normal.txt

│ │ └─ spam.txt

│ └─ Training

│ ├─ normal

│ │ ├─ 1.txt

│ │ ├─ 10.txt

│ │ ├─ 11.txt

│ │ ├─ …

│ └─ spam

│ ├─ 1.txt

│ ├─ 14.txt

│ ├─ 15.txt

│ ├─ …

2.数据预处理

邮件的具体内容基本类似:

机器学习:朴素贝叶斯的应用之垃圾邮件过滤_第7张图片

需要对每一封邮件进行切割处理,得到包含所有词语的列表

具体的分割方法参考Python读取有空行的txt文件+将内容分割保存到列表中

def load_file(path):
    cab = []
    for i in range(1,25):
        data = open(path % i)
        for line in data.readlines():
            cab.append(line.strip().split(','))
    cab_f = []
    for i in range(len(cab)):
        for j in range(len(cab[i])):
            if cab[i][j] != '':
                cab_f.append(cab[i][j].strip())
    cab_final = []
    for i in cab_f:
        for j in i.split(' '):
            cab_final.append(j)
    return cab_final

3.构造朴素贝叶斯分类器

def bayes(sample):
    path1 = './Emails/Training/normal/%d.txt'
    path2 = './Emails/Training/spam/%d.txt'
    normal_data = load_file(path1)
    spam_data = load_file(path2)
    # 计算p(x|C1)=p1与p(x|C2)=p2
    p1 = 1.0
    p2 = 1.0
    for i in range(len(sample)):
        x = 0.0
        for j in normal_data:
            if sample[i] == j:
                x = x + 1.0
        p1 = p1 * ((x + 1.0) / (len(normal_data) + 2.0))  # 拉普拉斯平滑

    for i in range(len(sample)):
        x = 0.0
        for j in spam_data:
            if sample[i] == j:
                x = x + 1.0
        p2 = p2 * ((x + 1.0) / (len(spam_data) + 2.0))  # 拉普拉斯平滑

    pc1 = len(normal_data) / (len(normal_data) + len(spam_data))
    pc2 = 1 - pc1

    if p1 * pc1 > p2 * pc2:
        return 'normal'
    else:
        return 'spam'

4.测试并获得测试结果

def test(path):
    data = open(path)
    cab = []
    for line in data.readlines():
        cab.append(line.strip().split(','))
    cab_f = []
    for i in range(len(cab)):
        for j in range(len(cab[i])):
            if cab[i][j] != '':
                cab_f.append(cab[i][j].strip())
    cab_final = []
    for i in cab_f:
        for j in i.split(' '):
            cab_final.append(j)
    return bayes(cab_final)


print(test('Emails/test/normal.txt'))
print(test('Emails/test/spam.txt'))

输出结果:

image-20221129135707029

算法对于测试集中的邮件分类是正确的。

查看算法在训练集上多个邮件分类时的准确率

if __name__ == '__main__':
    sum1 = 0
    sum2 = 0
    # 再试试训练集
    for i in range(1, 25):
        if test('Emails/Training/normal/%d.txt' % i) == 'normal':
            sum1 = sum1 + 1
    for i in range(1, 25):
        if test('Emails/Training/spam/%d.txt' % i) == 'spam':
            sum2 = sum2 + 1
    print('normal分类正确率:', sum1 / 24)
    print('spam分类正确率:', sum2 / 24)

输出结果:

image-20221129135828564

算法在训练集上的分类正确率很高,分类效果很好。

完整代码

import os

def load_file(path):
    cab = []
    for i in range(1,25):
        data = open(path % i)
        for line in data.readlines():
            cab.append(line.strip().split(','))
    cab_f = []
    for i in range(len(cab)):
        for j in range(len(cab[i])):
            if cab[i][j] != '':
                cab_f.append(cab[i][j].strip())
    cab_final = []
    for i in cab_f:
        for j in i.split(' '):
            cab_final.append(j)
    return cab_final


# 朴素贝叶斯分类器
def bayes(sample):
    path1 = './Emails/Training/normal/%d.txt'
    path2 = './Emails/Training/spam/%d.txt'
    normal_data = load_file(path1)
    spam_data = load_file(path2)
    # 计算p(x|C1)=p1与p(x|C2)=p2
    p1 = 1.0
    p2 = 1.0
    for i in range(len(sample)):
        x = 0.0
        for j in normal_data:
            if sample[i] == j:
                x = x + 1.0
        p1 = p1 * ((x + 1.0) / (len(normal_data) + 2.0))  # 拉普拉斯平滑

    for i in range(len(sample)):
        x = 0.0
        for j in spam_data:
            if sample[i] == j:
                x = x + 1.0
        p2 = p2 * ((x + 1.0) / (len(spam_data) + 2.0))  # 拉普拉斯平滑

    pc1 = len(normal_data) / (len(normal_data) + len(spam_data))
    pc2 = 1 - pc1

    if p1 * pc1 > p2 * pc2:
        return 'normal'
    else:
        return 'spam'


# 测试
def test(path):
    data = open(path)
    cab = []
    for line in data.readlines():
        cab.append(line.strip().split(','))
    cab_f = []
    for i in range(len(cab)):
        for j in range(len(cab[i])):
            if cab[i][j] != '':
                cab_f.append(cab[i][j].strip())
    cab_final = []
    for i in cab_f:
        for j in i.split(' '):
            cab_final.append(j)
    return bayes(cab_final)


if __name__ == '__main__':
    # print(test('Emails/test/normal.txt'))
    # print(test('Emails/test/spam.txt'))
    sum1 = 0
    sum2 = 0
    # 再试试训练集
    for i in range(1, 25):
        if test('Emails/Training/normal/%d.txt' % i) == 'normal':
            sum1 = sum1 + 1
    for i in range(1, 25):
        if test('Emails/Training/spam/%d.txt' % i) == 'spam':
            sum2 = sum2 + 1
    print('normal分类正确率:', sum1 / 24)
    print('spam分类正确率:', sum2 / 24)

你可能感兴趣的:(人工智能,python)