【Python机器学习】朴素贝叶斯——使用Python进行文本分类

news2024/9/20 18:51:15

目录

准备文本:从文本中构建词向量

训练算法:从词向量计算概率

测试算法:根据现实情况修改分类器

准备数据:文档词袋模型


要从文本中获取特征,需要先拆分文本。这里的特征是来自文本的词条,一个词条是字符的任意组合。可以把词条想象为单词,也可以使用非单词词条,如URL、IP地址或者任意其他字符串。然后将每一个文本片段表示为一个词条向量,其中值为1表示词条出现在文本中,0表示词条未出现。

以社区的留言板为例。为了不影响社区的发展,我们要屏蔽侮辱性的言论,所以要构建一个快速过滤器,如果发现某条留言使用了负面或者侮辱性的语言,那么就将该留言标识为内容不当。过滤这类内容是一个很常见的需求。对此问题建立两个类别:侮辱性和非侮辱性,使用1和0分别表示。

下面是将文本转换为数字向量的过程,然后基于这些向量来计算条件概率,并在此基础上构建分类器,最后是一些利用Python实现朴素贝叶斯过程中需要考虑的问题。

准备文本:从文本中构建词向量

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

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

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:
            #如果词汇出现在词汇表中,向量对应值为1,否则为0
            returnVec[vocabList.index(word)]=1
        else:
            print('%s 这个单词不在词汇表中!')
    return returnVec

上述代码中,第一个函数loadDataSet()创建了一些实验样本。该函数返回的第一个变量是进行词条切割后的文档集合,这些文档来自够累爱好者留言板。这些留言文本被切分成一系列的此条集合,标点符号从文本中去掉。loadDataSet()返回的第二个变量是一个类别标签的集合。这里有两类:侮辱性和非侮辱性。这些文本的类别由人工标注,这些标注信息用于训练程序一遍自动检测侮辱性留言。

createVocabList(dataSet)会创建一个包含在所有文档中出现的不重复词的列表,为此使用了Python的set数据类型。将词条列表输给set构造函数,set就会返回一个不重复词表。

获得词表后,使用setOfWords2Vec(vocabList,inputSet),该函数的输入参数为词汇表及某个文档,输出的是文档向量,向量的每一元素为1或0,分别表示词汇表中的单词在输入文档中是否出现。

观察效果:

listOPosts,listClasses=loadDataSet()
myVocabList=createVocabList(listOPosts)
print(myVocabList)

检查词表,可以看到这里没有重复的单词。

看下setOfWords2Vec()效果:

print(setOfWords2Vec(myVocabList,listOPosts[0]))
print(setOfWords2Vec(myVocabList,listOPosts[3]))

训练算法:从词向量计算概率

上面是将一组单词转换为数字的过程,接下来看如何使用数字计算概率。

现在已经知道一个词是否出现在一篇文档中,也知道该文档所属的类别,我们就可以计算贝叶斯公式:

p(c_{i}|w)=\frac{p(w|c_{i})p(c_{i})}{p(w)}

我们使用上述公式,对每个类计算该值,然后比较这两个概率值的大小。首先可以通过类别i(侮辱性留言或非侮辱性留言)中文档数除以总的文档数来计算概率P(c_{i})。接下来计算P(w|c_{i}),这里就要用到朴素贝叶斯假设。如果将w展开为一个个独立特征,那么就可以将上述概率写作P(w_{0},w_{1},w_{2},w_{3},w_{4}...w_{n}|c_{i})。这里假设所有词都相互独立,该假设也称为条件独立性假设,它意味着可以使用P(w_{0}|c_{i})P(w_{1}|c_{i})P(w_{2}|c_{i})...P(w_{n}|c_{i})来计算上述概率,这就极大地简化了计算过程。

函数的伪代码如下:

计算每个类别中的文档数目

对每篇训练文档:

    对每个类别:

        如果词条出现在文档中->增加该词条的计数值

        增加所有词条的计数值

对每个类别:

    对每个词条:

        将该词条的数目除以总词条数目得到条件概率

返回每个类别的条件概率

下面,开始实现上述伪代码:

def trainNBO(trainMatrix,trainCategory):
    numTrainDocs=len(trainMatrix)
    numWords=len(trainMatrix[0])
    pAbusive=sum(trainCategory)/float(numTrainDocs)
    #初始化概率
    p0Num=zeros(numWords)
    p1Num=zeros(numWords)
    p0Denom=0.0
    p1Denom=0.0
    #对每篇训练文档
    for i in range(numTrainDocs):
        #如果词条出现在文档中
        if trainCategory[i]==1:
            p1Num=p1Num+trainMatrix[i]
            p1Denom=p1Denom+sum(trainMatrix[i])
        else:
            p0Num=p0Num+trainMatrix[i]
            p0Denom=p0Denom+sum(trainMatrix[i])
    #对每个元素做除法
    p1Vect=p1Num/p1Denom
    p0Vect=p0Num/p0Denom
    return p0Vect,p1Vect,pAbusive

代码函数中的输入参数为文档矩阵trainMatrix以及由每篇文档类别标签所构成的向量trainCategory。首先,计算文档属于侮辱性文档(class=1)的概率,即P(1)。因为这是一个二类分类问题,所以可以通过1-P(1)得到P(0)。对于多分类问题,则需要对代码进行修改。

计算P(w_{i}|c_{1})P(w_{i}|c_{0}),需要初始化程序中的分子变量和分母变量。由于w中元素非常多,因此可以使用NumPy数组快速计算这些值。分母变量是一个元素个数等于词汇表大小的NumPy素组。在gor循环中,要遍历训练集trainMatrix中所有的文档。一旦某个词语(侮辱性或者正常词语)在某一文档出现,则该词对应的个数(p1Num或者p0Num)就加一。而且在所有的文档中,该文档的总次数也相应加一。对于两个类别都要进行同样的处理。

最后,对每个元素除以该类别中的总次数。利用NumPy很好实现,用一个数组除以浮点数即可,最后函数会返回两个向量和一个概率。

运行:

listOPosts,listClasses=loadDataSet()
myVocabList=createVocabList(listOPosts)
trainMat=[]
for postinDoc in listOPosts:
    trainMat.append(setOfWords2Vec(myVocabList,postinDoc))
p0V,p1V,pAb=trainNBO(trainMat,listClasses)
print(pAb)
print(p0V)

这就是任意文档属于侮辱性文档的概率。

我们发现文档属于侮辱性文档的概率pAb为0.5。下面是给定文档类别条件下词汇表中单词出现的频率。

测试算法:根据现实情况修改分类器

利用贝叶斯 分类器对文档进行分类时,要计算多个概率的乘积以获得文档属于某个类别的概率,即计算P(w_{0}|1)P(w_{1}|1)P(w_{2}|1)。如果其中一个概率值为0,那么最后的乘积也为0.为降低这种影响,可以将所有词的出现初始化为1,并将分母初始化为2.

修改代码:

    p0Num=ones(numWords)
    p1Num=ones(numWords)
    p0Denom=2.0
    p1Denom=2.0

另一个问题是下溢出,这是由于太多很小的数相乘造成的。当计算乘积时P(w_{0}|c_{i})P(w_{1}|c_{i})P(w_{2}|c_{i})...P(w_{n}|c_{i}),由于大部分因子都非常小,所以程序会下溢出或者得到不正确的答案。一种解决办法是对乘积取自然对数。在代数中有ln(a*b)=ln(a)+ln(b),于是通过求对数可以避免下溢出或者浮点数舍入导致的错误。同时,采用自然对数进行处理不会有任何损失。

修改代码:

    p1Vect=log(p1Num/p1Denom)
    p0Vect=log(p0Num/p0Denom)

现在已经准备好构造完整的分类器了。当使用NumPy向量处理功能时,这会十分简单:

def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
    #元素相乘
    p1=sum(vec2Classify*p1Vec)+log(pClass1)
    p0=sum(vec2Classify*p0Vec)+log(1.0-pClass1)
    if p1>p0:
        return 1
    else:
        return 0

def testingNB():
    listOPosts,listClasses=loadDataSet()
    myVocabList=createVocabList(listOPosts)
    trainMat=[]
    for postinDoc in listOPosts:
        trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
    p0V, p1V, pAb = trainNBO(trainMat, listClasses)
    testEntry=['love','my','dalmation']
    thisDoc=array(setOfWords2Vec(myVocabList,testEntry))
    print(testEntry,'classified as :',classifyNB(thisDoc,p0V,p1V,pAb))
    testEntry=['stupid','garbage']
    thisDoc=array(setOfWords2Vec(myVocabList,testEntry))
    print(testEntry,'classified as :',classifyNB(thisDoc,p0V,p1V,pAb))

classifyNB()函数有4个输入参数:要分类的向量vec2Classify,以及使用函数trainNB0()计算得到的三个概率值。使用NumPy的数组来计算两个向量相乘的结果。这里的相乘是指对应元素相乘,即先将两个向量中的第一个元素相乘,然后将第二个元素相乘,以此类推。接下来将词汇表中所有词的对应值相加,然后将该值加到类别的对数概率上。最后,比较类别的概率返回大概率对应的类别标签。

代码的第二个函数是一个便利函数,该函数封装所有操作,以节省时间。

运行结果:

上述例子展示了朴素贝叶斯分类器的工作原理。

准备数据:文档词袋模型

我们将每个词的出现与否作为一个特征,这可以被表述了词集模型。如果一个词在文档中出现不止一次,这可能意味着包含该词是否出现在文档中所不能表达的某种信息,这种方法被称为词袋模型。在词袋中,每个单词可以出现多次,而在词集中,每个词只能出现一次。为了适应词袋模型,需要对上面的setOfWords2Vec()稍作修改,修改后的函数称为bagOfWords2Vec()。

def bagOfWords2Vec(vocabList,inputSet):
    #创建一个其中包含元素都是0的向量
    returnVec=[0]*len(vocabList)
    for word in inputSet:
        if word in vocabList:
            #如果词汇出现在词汇表中,向量加1
            returnVec[vocabList.index(word)]=returnVec[vocabList.index(word)]+1
    return returnVec

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1953449.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大脑网络交互分析:公式与应用

大脑网络交互分析:公式与应用 核心概念与重要性 大脑网络交互分析是神经科学研究中的重要领域,它关注大脑不同区域之间的连接与交互方式。通过分析大脑网络,我们可以理解大脑如何处理和整合信息,进而揭示认知、情感和行为的神经…

java 集合框架-map(键值对集合)

一、Map接口 (键值对集合) 1.实现类 (1).线程不安全 HashMap 1.特点: ①无序 ②查找效率高:根据key,查找value 2.数据结构:数组(哈希表) 链表(链地址法解决哈希表冲突) 红黑树&#xff0…

UDP的报文结构及其注意事项

1. 概述 UDP(User Datagram Protocol)是一种无连接的传输层协议,它提供了一种简单的数据传输服务,不保证数据的可靠传输。在网络通信中,UDP通常用于一些对实时性要求较高、数据量较小、传输延迟较低的应用&#xff0c…

大数据的数据质量有效提升的研究

大数据的数据质量有效提升是一个涉及多个环节和维度的复杂过程。以下是从数据采集、处理、管理到应用等方面,对大数据数据质量有效提升的研究概述: 一、数据采集阶段 明确采集需求:在数据采集前,需明确数据需求,包括…

Mike21粒子追踪模型particle tracking如何展示粒子轨迹

前言: 随着模型的推广,模型的很多模块也问的多了起来,PT粒子追踪模块最近群友也在问,结果算了出来,却实现不了展示运动轨迹。今天就写段简单的PT后处理的方法吧。 注意:MIKE21输出模块中不但输出了关于水…

3个管人绝招,让下属心服口服

管人不能瞎管,手段很重要:3个管人绝招,让下属心服口服 一:差异化管理,玩弄人性 谁赞成,谁反对,看清楚谁顺从自己,谁反对自己之后,接下来要做的便是区别对待。 给听话的…

简单的CSS样式

样式分为三种 内部样式&#xff1a;写在html文件里的样式叫内部样式 内联样式&#xff1a;写在需要的标签中 外部样式&#xff1a;写在外部css文件里 可以通过不同的选择器来选择设置指定组件的样式&#xff1a; <style>/* 写在html文件里的样式叫内部样式 *//* 选择器 *…

PEFT LoRA 介绍(LoRA微调使用的参数及方法)

一 PEFT LoRA 介绍 官网简介如下图&#xff1a; 翻译过来是&#xff1a;低秩自适应(LoRA)是一种PEFT方法&#xff0c;它将一个大矩阵在注意层分解成两个较小的低秩矩阵。这大大减少了需要微调的参数数量。 说的只是针对注意力层&#xff0c;其实我自己平时微调操作注意力层多…

一款功能强大的视频编辑软件会声会影2023

会声会影2023是一款功能强大的视频编辑软件&#xff0c;由加拿大Corel公司制作&#xff0c;正版英文名称为‌Corel VideoStudio。它具备图像抓取和编修功能&#xff0c;可以处理和转换多种视频格式&#xff0c;如‌MV、‌DV、‌V8、‌TV和实时记录抓取画面文件。会声会影提供了…

微服务上(黑马)

文章目录 微服务011 认识微服务1.1 单体架构1.2 微服务1.3 SpringCloud 2 微服务拆分2.1 熟悉黑马商城2.2 服务拆分原则2.2.1.什么时候拆2.2.2.怎么拆 2.3 拆分服务2.3.1 拆分商品管理功能模块2.3.2 拆分购物车功能模块 2.4 远程调用2.4.1 RestTemplate2.4.2.远程调用 2.5 总结…

SpringBoot-21 SpringBoot微服务的发布与部署(3种方式)

基于 SpringBoot 的微服务开发完成之后&#xff0c;现在到了把它们发布并部署到相应的环境去运行的时候了。 SpringBoot 框架只提供了一套基于可执行 jar 包&#xff08;executable jar&#xff09;格式的标准发布形式&#xff0c;但并没有对部署做过多的界定&#xff0c;而且为…

25届最近5年广东工业大学自动化考研院校分析

广东工业大学 目录 一、学校学院专业简介 二、考试科目指定教材 三、近5年考研分数情况 四、近5年招生录取情况 五、最新一年分数段图表 六、初试大纲复试大纲 七、学费&奖学金&就业方向 一、学校学院专业简介 二、考试科目指定教材 1、考试科目介绍 2、指定教…

【在排序数组中查找元素的第一个和最后一个位置】python刷题记录

R2-分治 有点easy的感觉&#xff0c;感觉能用哈希表 class Solution:def searchRange(self, nums: List[int], target: int) -> List[int]:nlen(nums)dictdefaultdict(list)#初始赋值哈希表&#xff0c;记录出现次数for num in nums:if not dict[num]:dict[num]1else:dict[…

(深层与双向)循环神经网络

一、深层循环神经网络 1、对于循环神经网络 2、对于深层&#xff0c;要得到更多的非线性&#xff0c;就像多层感知机&#xff08;MLP&#xff09;。 &#xff08;1&#xff09;浅层与深层对比 这是具有&#x1d43f;个隐藏层的深度循环神经网络&#xff0c; 每个隐状态都连续…

【QT】QT 系统相关(事件、文件、多线程、网络、音视频)

一、Qt 事件 1、事件介绍 事件是应用程序内部或者外部产生的事情或者动作的统称。在 Qt 中使用一个对象来表示一个事件。所有的 Qt 事件均继承于抽象类 QEvent。事件是由系统或者 Qt 平台本身在不同的时刻发出的。当用户按下鼠标、敲下键盘&#xff0c;或者是窗口需要重新绘制…

《python程序语言设计》第6章14题 估算派值 类似莱布尼茨函数。但是我看不明白

这个题提供的公式我没看明白&#xff0c;后来在网上找到了莱布尼茨函数 c 0 for i in range(1, 902, 100):a (-1) ** (i 1)b 2 * i - 1c a / bprint(i, round(4 / c, 3))结果 #按题里的信息&#xff0c;但是结果不对&#xff0c;莱布尼茨函数到底怎么算呀。

【计算机网络】TCP协议详解

欢迎来到 破晓的历程的 博客 ⛺️不负时光&#xff0c;不负己✈️ 文章目录 1、引言2、udp和tcp协议的异同3、tcp服务器3.1、接口认识3.2、服务器设计 4、tcp客户端4.1、客户端设计4.2、说明 5、再研Tcp服务端5.1、多进程版5.2、多线程版 5、守护进程化5.1、什么是守护进程5.2…

Javascript面试基础6(下)

获取页面所有checkbox 怎样添加、移除、移动、复制、创建和查找节点 在JavaScript中&#xff0c;操作DOM&#xff08;文档对象模型&#xff09;是常见的任务&#xff0c;包括添加、移除、移动、复制、创建和查找节点。以下是一些基本的示例&#xff0c;说明如何执行这些操作&a…

【网络世界】HTTP协议

目录 &#x1f308;前言&#x1f308; &#x1f4c1; 概念 &#x1f4c1; URL &#x1f4c2; urlencode 和 urldecode &#x1f4c1; 协议格式 &#x1f4c1; 方法 &#x1f4c2; GET/get &#x1f4c2; POST/post &#x1f4c1; 常见的报头 &#x1f4c1; 状态码 &…

Web3 职场新手指南:从技能到素养,求职者如何脱颖而出?

随着 2024 年步入下半年&#xff0c;Web3 行业正在经历一系列技术革新。通过改进的跨链交互机制和兼容性&#xff0c;逐步消除市场碎片化的问题。技术的进步为开发者和用户都打开了新的前景。然而&#xff0c;复杂的技术和快速变化的市场环境也让许多新人望而却步。求职者如何找…