Python3《机器学习实战》学习笔记(四):朴素贝叶斯实战篇之新浪新闻分类

2023-10-29

一、朴素贝叶斯改进之拉普拉斯平滑

上篇文章提到过,算法存在一定的问题,需要进行改进。那么需要改进的地方在哪里呢?利用贝叶斯分类器对文档进行分类时,要计算多个概率的乘积以获得文档属于某个类别的概率,即计算p(w0|1)p(w1|1)p(w2|1)。如果其中有一个概率值为0,那么最后的成绩也为0。
在这里插入图片描述
可以看到很多0
如果新实例文本,包含这种概率为0的分词,那么最终的文本属于某个类别的概率也就是0了。

为了降低这种影响,可以将所有词的出现数初始化为1,并将分母初始化为2。这种做法就叫做拉普拉斯平滑(Laplace Smoothing)又被称为加1平滑,是比较常用的平滑方法,它就是为了解决0概率问题。

另外一个遇到的问题就是下溢出,这是由于太多很小的数相乘造成的。学过数学的人都知道,两个小数相乘,越乘越小,这样就造成了下溢出。为了解决这个问题,对乘积结果取自然对数。通过求对数可以避免下溢出或者浮点数舍入导致的错误。同时,采用自然对数进行处理不会有任何损失。

'''
函数说明:朴素贝叶斯分类器训练函数
trainMatrix - 训练文档矩阵,即setOfWords2Vec返回的returnVec构成的矩阵
trainCategory - 训练类别标签向量,即loadDataSet返回的classVec    [0,1,0,1,0,1]
'''
def trainNB0(trainMatrix, trainCategory):
    numTrainDocs = len(trainMatrix) # 计算训练文档数目
    numWords = len(trainMatrix[0])  # 计算每篇文档词条数
    pAbusive = sum(trainCategory) / float(numTrainDocs) # 文档属于侮辱类的概率

    # p0Num = np.zeros(numWords)
    # p1Num = np.zeros(numWords)  # 创建numpy.zeros数组,词条出现数初始化为0
    #
    # p0Denom = 0.0
    # p1Denom = 0.0  # 分母初始化为0

    p0Num = np.ones(numWords);
    p1Num = np.ones(numWords)  # 创建numpy.ones数组,词条出现数初始化为1,拉普拉斯平滑
    p0Denom = 2.0;
    p1Denom = 2.0  # 分母初始化为2,拉普拉斯平滑

    # 其实这里就是一个分类    把trainMatrix的每一行,分为两种,并且将两种分别累加
    for i in range(numTrainDocs):
        if(trainCategory[i] == 1):  # 这个if就相当于在已知
            p1Num += trainMatrix[i]
            p1Denom += sum(trainMatrix[i])

        else:
            p0Num += trainMatrix[i]
            p0Denom += sum(trainMatrix[i])

    print('p1Num:\n', p1Num)
    print('p1Denom:\n', p1Denom)
    print('p0Num:\n', p0Num)
    print('p0Denom:\n', p0Denom)
    # p1Vect = p1Num / p1Denom
    # p0Vect = p0Num / p0Denom

    p1Vect = np.log(p1Num / p1Denom)  # 取对数,防止下溢出         
    p0Vect = np.log(p0Num / p0Denom)

    return p0Vect, p1Vect, pAbusive

在这里插入图片描述

def classifyNB(wordVec, p0Vect, p1Vect, pAbusive):
    p0 = np.log(1.0 - pAbusive) + sum(wordVec * p0Vect)
    p1 = np.log(pAbusive) + sum(wordVec * p1Vect)
    if p0 > p1:
        return 0
    else:
        return 1

因为取自然对数了。logab = loga + logb。

这样,我们的朴素贝叶斯分类器就改进完毕了。

二、朴素贝叶斯之过滤垃圾邮件

2.1收集数据

有两个文件夹ham和spam,spam文件下的txt文件为垃圾邮件。

2.2完整代码

'''
@Project :MachineLearning 
@File    :emailBayes.py
@Author  :Kyrie Irving
@Date    :2022/10/27 10:41 
'''
import re
import numpy as np


def textParse(bigString):   #将字符串转换为字符列表
    listOfTokens = re.split(r'\W', bigString)                              #将特殊符号作为切分标志进行字符串切分,即非字母、非数字
    # listOfTokens = re.findall(r"[\w']+", bigString)
    return [li.lower() for li in listOfTokens if len(li) > 2]    #除了单个字母,例如大写的I,其它单词变成小写

'''
函数说明:将切分的实验样本词条整理成不重复的词条列表,也就是词汇表
'''
def createVocabList(dataSet):
    vocabSet = set([])
    for li in dataSet:
        vocabSet = vocabSet | set(li)   # 每一行去重复,再取交集,确保没重复行
    return list(vocabSet)

'''
函数说明:根据vocabList词汇表,将inputSet向量化,向量的每个元素为1或0
vocabList - createVocabList返回的列表
inputSet - 切分的词条列表,即原始数据的每一行
这里遍历每一行传入的每一个单词,如果单词在词汇表中出现了,在词汇表的相应下标位置置为1
'''
def setOfWords2Vec(vocabList, inputSet):
    returnVec = [0] * len(vocabList)    # 创建一个其中所含元素都为0的向量
    for word in inputSet:
        if word in vocabList:
            returnVec[vocabList.index(word)] = 1    # 如果词条存在于词汇表中,则置1
        else:
            print("the word: %s is not in my Vocabulary!" % word)
    return returnVec

'''
函数说明:根据vocabList词汇表,将inputSet向量化,向量的每个元素为1或0
vocabList - createVocabList返回的列表
inputSet - 切分的词条列表,即原始数据的每一行
这里遍历每一行传入的每一个单词,如果单词在词汇表中出现了,在词汇表的相应下标位置置为1
'''
def setOfWords2Vec(vocabList, inputSet):
    returnVec = [0] * len(vocabList)    # 创建一个其中所含元素都为0的向量
    for word in inputSet:
        if word in vocabList:
            returnVec[vocabList.index(word)] = 1    # 如果词条存在于词汇表中,则置1
        else:
            print("the word: %s is not in my Vocabulary!" % word)
    return returnVec

'''
函数说明:朴素贝叶斯分类器训练函数
trainMatrix - 训练文档矩阵,即setOfWords2Vec返回的returnVec构成的矩阵
trainCategory - 训练类别标签向量,即loadDataSet返回的classVec    [0,1,0,1,0,1]
'''
def trainNB0(trainMatrix, trainCategory):
    numTrainDocs = len(trainMatrix) # 计算训练文档数目
    numWords = len(trainMatrix[0])  # 计算每篇文档词条数
    pAbusive = sum(trainCategory) / float(numTrainDocs) # 文档属于侮辱类的概率


    p0Num = np.ones(numWords)
    p1Num = np.ones(numWords)  # 创建numpy.ones数组,词条出现数初始化为1,拉普拉斯平滑
    p0Denom = 2.0
    p1Denom = 2.0  # 分母初始化为2,拉普拉斯平滑

    # 其实这里就是一个分类    把trainMatrix的每一行,分为两种,并且将两种分别累加
    for i in range(numTrainDocs):
        if(trainCategory[i] == 1):  # 这个if就相当于在已知
            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
'''
wordVec必须是np.array()
因为后边需要其矩阵相乘
'''
def classifyNB(wordVec, p0Vect, p1Vect, pAbusive):
    p0 = np.log(1.0 - pAbusive) + sum(wordVec * p0Vect)
    p1 = np.log(pAbusive) + sum(wordVec * p1Vect)
    if p0 > p1:
        return 0
    else:
        return 1

def spamTest():
    docList = []
    classList = []
    for i in range(1, 26):
        fileName = 'spam/' + str(i) + '.txt'
        bigString = open(fileName, 'r').read()
        # wordList = textParse(open(fileName, 'r').read())
        wordList = textParse(open('spam/%d.txt' % i, 'r').read())  # 读取每个垃圾邮件,并字符串转换成字符串列表
        docList.append(wordList)
        classList.append(1)  # 标记垃圾邮件,1表示垃圾文件
        # wordList = textParse(open('ham/%d.txt' % i, 'r').read())  # 读取每个垃圾邮件,并字符串转换成字符串列表
        wordList = textParse(open('ham/%d.txt' % i, 'r').read())  # 读取每个垃圾邮件,并字符串转换成字符串列表
        docList.append(wordList)
        classList.append(0)  # 标记垃圾邮件,1表示垃圾文件

    vocabList = createVocabList(docList)  # 创建词汇表,不重复
    print('不重复的词汇表:', vocabList)

    trainingSet = list(range(50))   #创建存储训练集的索引值的列表和测试集的索引值的列表
    testSet = []

    for i in range(10): #从50个邮件中,随机挑选出40个作为训练集,10个做测试集
        rangIndex = int(np.random.uniform(0, len(trainingSet))) #随机选取索索引值
        testSet.append(trainingSet[rangIndex])  #添加测试集的索引值
        del (trainingSet[rangIndex])    #在训练集列表中删除添加到测试集的索引值

    trainMat = []
    trainClasses = []                                        #创建训练集矩阵和训练集类别标签系向量
    for docIndex in trainingSet:
        trainMat.append(setOfWords2Vec(vocabList, docList[docIndex]))
        trainClasses.append(classList[docIndex])
    p0V, p1V, pSpam = trainNB0(np.array(trainMat), np.array(trainClasses))  #训练朴素贝叶斯模型

    errorCount = 0  # 错误分类计数
    for docIndex in testSet:
        wordVector = setOfWords2Vec(vocabList, docList[docIndex])
        if classifyNB(np.array(wordVector), p0V, p1V, pSpam) != classList[docIndex]:   #如果分类错误
            errorCount += 1
            print("分类错误的测试集:", docList[docIndex])
    print('错误率:%.2f%%' % (float(errorCount) / len(testSet) * 100))

if __name__ == '__main__':
    spamTest()

在这里插入图片描述
在这里插入图片描述
既然这些电子邮件是随机选择的,所以每次的输出结果可能有些差别。

三、朴素贝叶斯之新浪新闻分类(Sklearn)

后续链接: https://jackcui.blog.csdn.net/article/details/77500679

四、总结

  1. 在训练朴素贝叶斯分类器之前,要处理好训练集,文本的清洗还是有很多需要学习的东西。
  2. 根据提取的分类特征将文本向量化,然后训练朴素贝叶斯分类器。分类的时候也是一样的
  3. 去高频词汇数量的不同,对结果也是有影响的的。
  4. 拉普拉斯平滑对于改善朴素贝叶斯分类器的分类效果有着积极的作用。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python3《机器学习实战》学习笔记(四):朴素贝叶斯实战篇之新浪新闻分类 的相关文章

随机推荐

  • vscode Java开发环境搭建

    java系列文章目录 文章目录 java系列文章目录 前言 本文的目的 一 安装Java Extension Pack插件 二 配置全局的Java与Maven 三 开始创建Maven项目 四 配置该项目的settings json 五 补全
  • 自制无盘更新服务器,无盘云更新安装服务器流程

    无盘云更新安装服务器流程 内容精选 换一换 在 云服务器列表 页 单击 操作 列下的 查看应用 查看应用的状态为 安装失败 将鼠标移动至 安装失败 处 查看具体的失败原因 并根据表1进行故障排除 CVR服务端支持使用的应用需要满足以下条件
  • 不简单的单例模式Singleton

    版权声明 本文为博主原创文章 未经博主允许不得转载 单例模式 即Ensure a class only has one instance and provide a global point of access to it 只有一个实例 是
  • 猎头推荐成功一个人竟然收年薪一半,也太赚了吧

    猎头推荐成功一个人竟然收年薪一半 也太赚了吧 这个问题似乎有点危言耸听了 有网友说女朋友是猎头 推荐成功并没有提成 要一个季度内推多少个之后 之后再成的才有30 提成 当然每个公司情况都不一样 很多猎头是不挣钱的 公司有成本线 超出成本线你
  • 【QT】Mac电脑(苹果电脑)Qt 菜单栏不显示的问题解决办法

    QT Mac电脑 苹果电脑 Qt 菜单栏不显示的问题解决办法 我所遇到的问题 并不是qt for mac 不显示菜单栏 而是菜单栏显示到Mac 菜单栏上去了 我想让Qt 菜单栏显示位置和win 系统下一样 不管是在纯代码环境和UI 设计环境
  • 水仙花数JAVA代码实现

    java代码实现求取水仙花数 水仙花数 Narcissistic number 也被称为超完全数字不变数 pluperfect digital invariant PPDI 自恋数 自幂数 阿姆斯壮数或阿姆斯特朗数 Armstrong nu
  • js 刷新页面但是不闪烁_Js历史

    1 Js是为了赶上java的潮流 把名字从LiveScript改为JavaScript 2 Js出现原因 最初的输入验证必须把表单数据发到服务端上才能验证 而最初的js是为了解决这个问题 3 Web浏览器只是js实现的可能的宿主环境之一 其
  • C - Candy Machine 二分

    传送门 题意 JB非常喜欢糖果 有一天 他发现了一台糖果机 里面有 N里面有糖果 看完机器的说明书后 他知道他可以选择一个子集 N糖果 每颗糖果都有一个甜味价值 JB 选择子集后 假设所选糖果的平均甜度值为 X 所有甜度值严格大于的糖果 X
  • 可以写进简历的软件测试电商项目(超详细版),不进来get一下?

    前言 说实话 在找项目的过程中 我下载过 甚至付费下载过 N多个项目 联系过很多项目的作者 但是绝大部分项目 在我看来 并不适合你拿来练习 它们或多或少都存在着 问题 比如 1 大部分项目是web项目 很难找到app项目 特别是有app安装
  • svn 服务器忽略文件夹,SVN忽略不提交文件夹

    层次分析模型 AHP 及其MATLAB实现 今天用将近一天的时间学习了层次分析模型 AHP 主要参考了一份pdf 这个网站 和暨南大学章老师的课件 现写出一些自己总结的要点 一 层次分析法的基本步骤 角度一 实际问题 分解 gt SQL S
  • spring 总结

    1 spring是什么 是一个开源的控制反转和面向切面的容器框架 2 控制反转就是应用本身不负责依赖对象的创建和维护 依赖对象的创建和维护是由外部容器负责的 这样控制权就由应用转移到了外部容器 控制权的转移就是所谓反转 3 依赖注入 在运行
  • 有头链表实现(C++描述)

    有头链表实现 include
  • PAT(Advanced Level)刷题指南 —— 第八弹

    一 1015 Reversible Primes 进制转换 质数判定 1 问题描述 不断给出两个数 N 和 D 直到输入负数终止 判断 N 是否为素数 并以 D 为基数倒转该数后 判断转化为 10进制 后还是不是素数 如果都满足 就输出Ye
  • [数值计算-19]:万能的任意函数的数值求导数方法

    作者主页 文火冰糖的硅基工坊 文火冰糖 王文兵 的博客 文火冰糖的硅基工坊 CSDN博客 本文网址 https blog csdn net HiWangWenBing article details 120378620 目录 第1章 前言
  • C++ inline内联函数详解

    函数是一个可以重复使用的代码块 CPU 会一条一条地挨着执行其中的代码 CPU 在执行主调函数代码时如果遇到了被调函数 主调函数就会暂停 CPU 转而执行被调函数的代码 被调函数执行完毕后再返回到主调函数 主调函数根据刚才的状态继续往下执行
  • for循环2(python)

    在python中 for循环的功能更加强大 对于可迭代对象的遍历更加的方便 可迭代对象 字符串 列表 元组等可以通过下标来访问元素的数据类型 同时这种数据类型也可以使用切片 例如我们遍历一个字符串 str hello for i in st
  • python时间序列动图_Python绘制时间序列数据的时序图、自相关图和偏自相关图

    时序图 自相关图和偏相关图是判断时间序列数据是否平稳的重要依据 本文涉及的扩展库numpy pandas statsmodels一般可以使用pip进行在线安装 如果安装失败 可以到http www lfd uci edu gohlke py
  • Java 基本命名规则

    一 项目名称 所有单词全部用小写 如 testjavaproject studentmanagement等 二 Java project中相关命名 1 包名 包名统一使用小写 点分隔符之间有且仅有一个自然语义的英语单词 用域名反过来写 不会
  • 关于uni-app课程开发的一心一得

    在当今互联网和移动互联网的时代 APP成为了人们生活和工作中不可或缺的一部分 而对于开发者来说 如何快速 高效 跨平台地开发一款APP也成为了关注焦点 而Uni App就是一种可以快速开发跨平台APP的方式 通过一套代码可以同时发布到多个平
  • Python3《机器学习实战》学习笔记(四):朴素贝叶斯实战篇之新浪新闻分类

    一 朴素贝叶斯改进之拉普拉斯平滑 上篇文章提到过 算法存在一定的问题 需要进行改进 那么需要改进的地方在哪里呢 利用贝叶斯分类器对文档进行分类时 要计算多个概率的乘积以获得文档属于某个类别的概率 即计算p w0 1 p w1 1 p w2