【机器学习实战】4、基于概率论的分类方法:朴素贝叶斯

2023-11-10

朴素贝叶斯(naive Bayes)算法是基于贝叶斯定理与特征条件独立假设的分类方法,对于给定的训练数据集,首先基于特征条件独立假设学习输入/输出的联合概率分布,然后基于此模型,对给定的输入x,利用贝叶斯定理求出后验概率最大的输出y,朴素贝叶斯法实现简单,学习与预测的效率都很高,是一种常见的方法。

朴素贝叶斯(naive Bayes)算法是有监督的学习算法,解决的是分类问题,如客户是否流失、是否值得投资、信用等级评定等多分类问题。该算法的优点在于简单易懂、学习效率高、在某些领域的分类问题中能够与决策树、神经网络相媲美。但由于该算法以自变量之间的独立(条件特征独立)性和连续变量的正态性假设为前提,就会导致算法精度在某种程度上受影响。

4.1 基于贝叶斯决策理论的分类方法

  • 优点:在数据较少的情况下仍然有效,可以处理多类别问题
  • 缺点:对于输入数据的准备方式较为敏感
  • 适用数据类型:标称型数据

4.1.1 贝叶斯决策理论

朴素贝叶斯是贝叶斯决策理论的一部分,所以首先了解一下贝叶斯理论。

假设现在我们有一个数据集,它由两类数据组成,

我们现在用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概率。

4.1.2 条件概率

在学习计算p1和p2概率之前,我们需要了解什么是条件概率(Condittional probability),就是指在事件B发生的情况下,事件A发生的概率,用 P ( A ∣ B ) P(A|B) P(AB)来表示。
P ( A ∣ B ) = P ( A ⋂ B ) P ( B ) P(A|B)=\frac{P(A \bigcap B)}{P(B)} P(AB)=P(B)P(AB)
故:
P ( A ⋂ B ) = P ( A ∣ B ) P ( B ) P(A\bigcap B)={P(A|B)}{P(B)} P(AB)=P(AB)P(B)
同理:
P ( A ⋂ B ) = P ( B ∣ A ) P ( A ) P(A\bigcap B)={P(B|A)}{P(A)} P(AB)=P(BA)P(A)
所以:
P ( A ∣ B ) P ( B ) = P ( B ∣ A ) P ( A ) P(A|B)P(B)=P(B|A)P(A) P(AB)P(B)=P(BA)P(A)
即:
P ( A ∣ B ) = P ( B ∣ A ) P ( A ) P ( B ) P(A|B)=\frac{P(B|A)P(A)}{P(B)} P(AB)=P(B)P(BA)P(A)
上式即为条件概率的计算公式

4.1.3 全概率公式

除了条件概率以外,在计算p1和p2的时候,还要用到全概率公式,因此,这里继续推导全概率公式。

P ( B ) = P ( B ⋂ A ) + P ( B ⋂ A ′ ) P(B)=P(B\bigcap A)+P(B\bigcap A') P(B)=P(BA)+P(BA)
已知:
P ( B ⋂ A ) = + P ( B ∣ A ) P ( A ) P(B\bigcap A)=+P(B|A)P(A) P(BA)=+P(BA)P(A)
故全概率公式为:
P ( B ) = P ( B ∣ A ) P ( A ) + P ( B ∣ A ′ ) P ( A ′ ) P(B)=P(B|A)P(A)+P(B|A')P(A') P(B)=P(BA)P(A)+P(BA)P(A)

其含义为:如果 A A A A ′ A' A构成一个样本空间的一个划分,那么事件 B B B的概率就等于 A A A A ′ A' A的概率分别乘以 B B B对这两个事件的条件概率之和。

于是条件概率就有了另一种写法:
P ( A ∣ B ) = P ( B ∣ A ) P ( A ) P ( B ∣ A ) P ( A ) + P ( B ∣ A ′ ) P ( A ′ ) P(A|B)=\frac{P(B|A)P(A)}{P(B|A)P(A)+P(B|A')P(A')} P(AB)=P(BA)P(A)+P(BA)P(A)P(BA)P(A)

4.1.4 贝叶斯推断

对条件概率进行变形,可以得到如下形式:

P ( A ∣ B ) = P ( A ) P ( B ∣ A ) P ( B ) P(A|B)=P(A)\frac{P(B|A)}{P(B)} P(AB)=P(A)P(B)P(BA)

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

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

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

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

后验概率 = 先验概率 ∗ 调整因子 后验概率=先验概率*调整因子 后验概率=先验概率调整因子

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

在这里,如果”可能性函数”P(B|A)/P(B)>1,意味着”先验概率”被增强,事件A的发生的可能性变大;如果”可能性函数”=1,意味着B事件无助于判断事件A的可能性;如果”可能性函数”<1,意味着”先验概率”被削弱,事件A的可能性变小。

4.1.5 朴素贝叶斯

“朴素”的解释:假设各个特征之间相互独立(在贝叶斯分类器上做了简化)
朴素贝叶斯的基础假设:

①每个特征相互独立;
②每个特征的权重(或重要性)都相等,即对结果的影响程度都相同。

举例说明:

某个医院早上来了六个门诊的病人,他们的情况如下表所示:

症状 职业 疾病
打喷嚏 护士 感冒
打喷嚏 农夫 过敏
头痛 建筑工人 脑震荡
头痛 建筑工人 感冒
打喷嚏 教师 感冒
头痛 教师 脑震荡

现在又来了第七个病人,是一个打喷嚏的建筑工人。请问他患上感冒的概率有多大?

根据贝叶斯定理:

P ( A ∣ B ) = P ( B ∣ A ) P ( A ) P ( B ) P(A|B)=\frac {P(B|A)P(A)}{P(B)} P(AB)=P(B)P(BA)P(A)

可得:

P(感冒|打喷嚏&建筑工人)=P(打喷嚏&建筑工人|感冒)P(感冒) / P(打喷嚏&建筑工人)

根据朴素贝叶斯条件独立假设可知,打喷嚏和建筑工人两个特征是独立的,所以:

P(感冒|打喷嚏&建筑工人)=P(打喷嚏|感冒)P(建筑工人|感冒P(感冒) / P(打喷嚏&建筑工人)

P(感冒|打喷嚏&建筑工人)=0.66x0.33x0.5/(0.5x0.33)=0.66

因此,这个打喷嚏的建筑工人,有66%的概率是得了感冒。同理,可以计算这个病人患上过敏或脑震荡的概率。比较这几个概率,就可以知道他最可能得什么病。

这就是贝叶斯分类器的基本方法:在统计资料的基础上,依据某些特征,计算各个类别的概率,从而实现分类。

同样,在编程的时候,如果不需要求出所属类别的具体概率,P(打喷嚏) = 0.5和P(建筑工人) = 0.33的概率是可以不用求的。

4.2 使用朴素贝叶斯进行文档分类

朴素贝叶斯是上节介绍的贝叶斯分类器的一个扩展,是用于文档分类的常用算法。

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

我们把文本看成单词向量或者词条向量,也就是说将句子转换为向量。考虑出现所有文档中的单词,再决定将哪些单词纳入词汇表或者说所要的词汇集合,然后必须要将每一篇文档转换为词汇表上的向量。简单起见,我们先假设已经将本文切分完毕,存放到列表中,并对词汇向量进行分类标注。编写代码如下:

函数说明:创建实验样本

Parameters:
    无
Returns:
    postingList:实验样本切分的词条
    classVec:类别标签向量
Modify:
    2018-03-14

"""
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']]
    # 类别标签向量,1代表侮辱性词汇,0代表不是
    classVec = [0, 1, 0, 1, 0, 1]
    return postingList, classVec

if __name__=='__main__':
    postingList,classVec=loadDataSet()
    for each in postingList:
        print(each)
    print(classVec)

创建一个词汇表,并将切好的词条转化为词条向量

"""
函数说明:创建实验样本

Parameters:
    无
Returns:
    postingList:实验样本切分的词条
    classVec:类别标签向量
Modify:
    2018-03-14

"""
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']]
    # 类别标签向量,1代表侮辱性词汇,0代表不是
    classVec = [0, 1, 0, 1, 0, 1]
    return postingList, classVec

"""
函数说明:更加vocabList词汇表,将inputSet向量化,向量的每个元素为1或0

Parameters:
    vocabList:createVocabList返回的列表
    inputSet:切分的词条列表
Returns:
    returnVec:文档向量,词集模型
Modify:
    2018-03-14

"""
def setOfWords2Vec(vocabList,inputSet):
    #创建一个其中所含元素都为0的向量
    returnVec=[0]*len(vocabList)
    #遍历每个词条
    for word in inputSet:
        #如果词条存在于词汇表中,则置1
        if word in vocabList:
            returnVec[vocabList.index(word)]=1
        else:print("the word: %s is not in my Vocabulary!" % word)
    #返回向量文档
    return returnVec

""""
函数说明:将切分的实验样本词条整理成不重复的词条列表,也就是词汇表

Parameters:
    dataSet:整理的样本数据集
Returns:
    vocabSet:返回不重复的词条列表,也就是词汇表
Modify:
    2018-03-14

"""
def createVocabList(dataSet):
    #创建一个空的不重复列表
    vocabSet=set([])
    for document in dataSet:
        #取并集
        vocabSet=vocabSet|set(document)
    return list(vocabSet)

if __name__=='__main__':
    postingList,classVec=loadDataSet()
    print('postingList:\n',postingList)
    myVocabList=createVocabList(postingList)
    print('myVocabList:\n',myVocabList)
    trainMat=[]
    for postinDoc in postingList:
        trainMat.append(setOfWords2Vec(myVocabList,postinDoc))
    print('trainMat:\n',trainMat)


从运行结果可以看出,postingList是原始的词条列表,myVocabList是词汇表。myVocabList是所有单词出现的集合,没有重复的元素。词汇表是用来干什么的?没错,它是用来将词条向量化的,一个单词在词汇表中出现过一次,那么就在相应位置记作1,如果没有出现就在相应位置记作0。trainMat是所有的词条向量组成的列表。它里面存放的是根据myVocabList向量化的词条向量。

我们已经得到了词条向量。接下来,我们就可以通过词条向量训练朴素贝叶斯分类器。

import numpy as np

"""
函数说明:创建实验样本

Parameters:
    无
Returns:
    postingList:实验样本切分的词条
    classVec:类别标签向量
Modify:
    2018-03-14

"""
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']]
    # 类别标签向量,1代表侮辱性词汇,0代表不是
    classVec = [0, 1, 0, 1, 0, 1]
    return postingList, classVec

"""
函数说明:更加vocabList词汇表,将inputSet向量化,向量的每个元素为1或0

Parameters:
    vocabList:createVocabList返回的列表
    inputSet:切分的词条列表
Returns:
    returnVec:文档向量,词集模型
Modify:
    2018-03-14

"""
def setOfWords2Vec(vocabList,inputSet):
    #创建一个其中所含元素都为0的向量
    returnVec=[0]*len(vocabList)
    #遍历每个词条
    for word in inputSet:
        #如果词条存在于词汇表中,则置1
        if word in vocabList:
            returnVec[vocabList.index(word)]=1
        else:print("the word: %s is not in my Vocabulary!" % word)
    #返回向量文档
    return returnVec

""""
函数说明:将切分的实验样本词条整理成不重复的词条列表,也就是词汇表

Parameters:
    dataSet:整理的样本数据集
Returns:
    vocabSet:返回不重复的词条列表,也就是词汇表
Modify:
    2018-03-14

"""
def createVocabList(dataSet):
    #创建一个空的不重复列表
    vocabSet=set([])
    for document in dataSet:
        #取并集
        vocabSet=vocabSet|set(document)
    return list(vocabSet)

"""
函数说明:朴素贝叶斯分类器训练函数

Parameters:
    trainMatrix:训练文档矩阵,即setOfWords2Vec返回的returnVec构成的矩阵
    trainCategory:训练类别标签向量,即loadDataSet返回的classVec
Returns:    
    p0Vect:侮辱类的条件概率数组
    p1Vect:非侮辱类的条件概率数组
    pAbusive:文档属于侮辱类的概率
Modify:
    2018-03-14

"""
def trainNB0(trainMtrix,trainCategory):
    #计算训练的文档数目
    numTrainDocs=len(trainMtrix)
    #计算每篇文章的词条数
    numWords=len(trainMtrix[0])
    #文档属于侮辱类的概率
    pAbusive=sum(trainCategory)/float(numTrainDocs)
    #创建numpy.zeros数组
    p0Num=np.zeros(numWords);p1Num=np.zeros(numWords)
    #分母初始化为0.0
    p0Denom=0.0;p1Denom=0.0
    
    for i in range(numTrainDocs):
        #统计属于侮辱类的条件概率
        if trainCategory[i]==1:
            p1Num+=trainMtrix[i]
            p1Denom+=sum(trainMtrix[i])
        #统计属于非侮辱类的条件概率
        else:
            p0Num+=trainMtrix[i]
            p0Denom+=sum(trainMtrix[i])
    #相除
    p1Vect=p1Num/p1Denom
    p0Vect=p0Num/p1Denom
    #返回属于侮辱类的条件概率
    return p0Vect,p1Vect,pAbusive

if __name__=='__main__':
    postingList,classVec=loadDataSet()

    myVocabList=createVocabList(postingList)
    print('myVocabList:\n',myVocabList)

    trainMat=[]
    for postinDoc in postingList:
        trainMat.append(setOfWords2Vec(myVocabList,postinDoc))

    p0V,p1V,pAb=trainNB0(trainMat,classVec)
    print('p0V:\n',p0V)
    print('p1V:\n', p1V)
    print('classVec:\n', classVec)
    print('pAb:\n', pAb)

p0V 存放的是每个单词属于类别0,也就是非侮辱类词汇的概率
p1V 存放的就是各个单词属于侮辱类的条件概率。pAb就是先验概率。

已经训练好分类器,接着用分类器进行分类

import numpy as np
from functools import reduce
"""
函数说明:创建实验样本

Parameters:
    无
Returns:
    postingList:实验样本切分的词条
    classVec:类别标签向量
Modify:
    2018-03-14

"""


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']]
    # 类别标签向量,1代表侮辱性词汇,0代表不是
    classVec = [0, 1, 0, 1, 0, 1]
    return postingList, classVec


"""
函数说明:更加vocabList词汇表,将inputSet向量化,向量的每个元素为1或0

Parameters:
    vocabList:createVocabList返回的列表
    inputSet:切分的词条列表
Returns:
    returnVec:文档向量,词集模型
Modify:
    2018-03-14

"""


def setOfWords2Vec(vocabList, inputSet):
    # 创建一个其中所含元素都为0的向量
    returnVec = [0] * len(vocabList)
    # 遍历每个词条
    for word in inputSet:
        # 如果词条存在于词汇表中,则置1
        if word in vocabList:
            returnVec[vocabList.index(word)] = 1
        else:
            print("the word: %s is not in my Vocabulary!" % word)
    # 返回向量文档
    return returnVec


""""
函数说明:将切分的实验样本词条整理成不重复的词条列表,也就是词汇表

Parameters:
    dataSet:整理的样本数据集
Returns:
    vocabSet:返回不重复的词条列表,也就是词汇表
Modify:
    2018-03-14

"""


def createVocabList(dataSet):
    # 创建一个空的不重复列表
    vocabSet = set([])
    for document in dataSet:
        # 取并集
        vocabSet = vocabSet | set(document)
    return list(vocabSet)


"""
函数说明:朴素贝叶斯分类器训练函数

Parameters:
    trainMatrix:训练文档矩阵,即setOfWords2Vec返回的returnVec构成的矩阵
    trainCategory:训练类别标签向量,即loadDataSet返回的classVec
Returns:    
    p0Vect:侮辱类的条件概率数组
    p1Vect:非侮辱类的条件概率数组
    pAbusive:文档属于侮辱类的概率
Modify:
    2018-03-14

"""


def trainNB0(trainMtrix, trainCategory):
    # 计算训练的文档数目
    numTrainDocs = len(trainMtrix)
    # 计算每篇文章的词条数
    numWords = len(trainMtrix[0])
    # 文档属于侮辱类的概率
    pAbusive = sum(trainCategory) / float(numTrainDocs)
    # 创建numpy.zeros数组
    p0Num = np.zeros(numWords);
    p1Num = np.zeros(numWords)
    # 分母初始化为0.0
    p0Denom = 0.0;
    p1Denom = 0.0

    for i in range(numTrainDocs):
        # 统计属于侮辱类的条件概率
        if trainCategory[i] == 1:
            p1Num += trainMtrix[i]
            p1Denom += sum(trainMtrix[i])
        # 统计属于非侮辱类的条件概率
        else:
            p0Num += trainMtrix[i]
            p0Denom += sum(trainMtrix[i])
    # 相除
    p1Vect = p1Num / p1Denom
    p0Vect = p0Num / p1Denom
    # 返回属于侮辱类的条件概率
    return p0Vect, p1Vect, pAbusive

"""
函数说明:朴素贝叶斯分类器分类函数

Parameters:
    vec2Classifyaaa:待分类的词条数组
    p0Vec:侮辱类的条件概率数组
    p1Vec:非侮辱类的条件概率数组
    pClass1:文档属于侮辱类的概率
Returns:
    0 :属于非侮辱类
    1 :属于侮辱类
Modify:
    2018-03-14
"""
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
    #对应元素相乘
    p1=reduce(lambda x,y:x*y,vec2Classify*p1Vec)*pClass1
    p0=reduce(lambda x,y:x*y,vec2Classify*p0Vec)*(1.0-pClass1)
    print('p0:',p0)
    print('p1:',p1)
    if p1>p0:
        return 1
    else:
        return 0

"""
函数说明:测试朴素贝叶斯分类器

Parameters:
    无
Returns:
    无
Modify:
    2018-03-14
"""
def testingNB():
    #创建实验样本
    listOPosts,listClasses=loadDataSet()
    #创建词汇表
    myVocabList=createVocabList((listOPosts))

    trainMat=[]
    for postinDoc in listOPosts:
        #将实验样本向量化
        trainMat.append(setOfWords2Vec(myVocabList,postinDoc))
    #训练朴素贝叶斯分类器
    p0V,p1V,pAb=trainNB0(np.array(trainMat),np.array(listClasses))
    #测试样本1
    testEntry=['love','my','dalmation']
    #测试样本向量化
    thisDoc=np.array(setOfWords2Vec(myVocabList,testEntry))
    #执行分类并打印分类结果
    if classifyNB(thisDoc,p0V,p1V,pAb):
        print(testEntry,'属于侮辱类')
    # 执行分类并打印分类结果
    else:
        print(testEntry,'属于非侮辱类')
    #测试样本2
    testEntry=['stupid','garbage']
    
    #测试样本向量化
    thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
    # 执行分类并打印分类结果
    if classifyNB(thisDoc, p0V, p1V, pAb):
        print(testEntry, '属于侮辱类')
        # 执行分类并打印分类结果
    else:
        print(testEntry, '属于非侮辱类')  

if __name__ == '__main__':
    testingNB()

我们发现,p0和p1的计算结果都是0,下面来探讨产生该结果的问题。

4.3 总结

朴素贝叶斯推断的一些优点:

  • 生成式模型,通过计算概率来进行分类,可以用来处理多分类问题。
  • 对小规模的数据表现很好,适合多分类任务,适合增量式训练,算法也比较简单。

朴素贝叶斯推断的一些缺点:

  • 对输入数据的表达形式很敏感。
  • 由于朴素贝叶斯的“朴素”特点,所以会带来一些准确率上的损失。
  • 需要计算先验概率,分类决策存在错误率。

4.4 朴素贝叶斯改进——拉普拉斯平滑

1)零概率问题

造成原因:

利用贝叶斯分类器对文档进行分类时,要计算多个概率的乘积以获得文档属于某个类别的概率,即计算 p ( w 0 ∣ A ) p ( w 1 ∣ A ) p ( w 2 ∣ A ) p(w0|A)p(w1|A)p(w2|A) p(w0∣A)p(w1∣A)p(w2∣A),如果其中有一个为0,则最后的结果也为0。

解决方法:

为了降低这种影响,可以将所有词的出现次数初始化为1,并将分母初始化为2,这种做法称为“拉普拉斯平滑”,也称“加1平滑”,是比较常用的平滑方法,为了解决0概率问题。

2)下溢出

造成的原因:

是太多很小的数相乘,越乘越小,就造成了下溢出的问题。在相应小数位置进行四舍五入,计算结果可能就变成0了。

解决方法:

对乘积结果取自然对数,通过求对数可以避免下溢出或者浮点数舍入导致的错误,同时,采用自然对数进行处理不会有任何损失。

上图显示了 f ( x ) f(x) f(x) l n f ( x ) lnf(x) lnf(x)的曲线,可以看出上面两条曲线同增同减,且最大值处相同,取值虽然不同,但是不影响最终结果。

因此,可以对trainNB0函数进行修改:

import numpy as np

"""
函数说明:创建实验样本

Parameters:
    无
Returns:
    postingList:实验样本切分的词条
    classVec:类别标签向量
Modify:
    2018-03-14

"""
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']]
    # 类别标签向量,1代表侮辱性词汇,0代表不是
    classVec = [0, 1, 0, 1, 0, 1]
    return postingList, classVec

"""
函数说明:更加vocabList词汇表,将inputSet向量化,向量的每个元素为1或0

Parameters:
    vocabList:createVocabList返回的列表
    inputSet:切分的词条列表
Returns:
    returnVec:文档向量,词集模型
Modify:
    2018-03-14

"""
def setOfWords2Vec(vocabList,inputSet):
    #创建一个其中所含元素都为0的向量
    returnVec=[0]*len(vocabList)
    #遍历每个词条
    for word in inputSet:
        #如果词条存在于词汇表中,则置1
        if word in vocabList:
            returnVec[vocabList.index(word)]=1
        else:print("the word: %s is not in my Vocabulary!" % word)
    #返回向量文档
    return returnVec

""""
函数说明:将切分的实验样本词条整理成不重复的词条列表,也就是词汇表

Parameters:
    dataSet:整理的样本数据集
Returns:
    vocabSet:返回不重复的词条列表,也就是词汇表
Modify:
    2018-03-14

"""
def createVocabList(dataSet):
    #创建一个空的不重复列表
    vocabSet=set([])
    for document in dataSet:
        #取并集
        vocabSet=vocabSet|set(document)
    return list(vocabSet)

"""
函数说明:朴素贝叶斯分类器训练函数

Parameters:
    trainMatrix:训练文档矩阵,即setOfWords2Vec返回的returnVec构成的矩阵
    trainCategory:训练类别标签向量,即loadDataSet返回的classVec
Returns:    
    p0Vect:侮辱类的条件概率数组
    p1Vect:非侮辱类的条件概率数组
    pAbusive:文档属于侮辱类的概率
Modify:
    2018-03-14

"""
def trainNB0(trainMtrix, trainCategory):
    # 计算训练的文档数目
    numTrainDocs = len(trainMtrix)
    # 计算每篇文章的词条数
    numWords = len(trainMtrix[0])
    # 文档属于侮辱类的概率
    pAbusive = sum(trainCategory) / float(numTrainDocs)
    # 创建numpy.ones数组,词条初始化为1,拉普拉斯平滑
    p0Num = np.ones(numWords);
    p1Num = np.ones(numWords)
    # 分母初始化为2.0,拉普拉斯平滑
    p0Denom = 2.0
    p1Denom = 2.0

    for i in range(numTrainDocs):
        # 统计属于侮辱类的条件概率所需的数据,即P(w0|1),P(w1|1),P(w2|1)···
        if trainCategory[i] == 1:
            p1Num += trainMtrix[i]
            p1Denom += sum(trainMtrix[i])
        # 统计属于非侮辱类的条件概率所需的数据,即P(w0|0),P(w1|0),P(w2|0)···
        else:
            p0Num += trainMtrix[i]
            p0Denom += sum(trainMtrix[i])
    # 相除
    p1Vect = np.log(p1Num / p1Denom)
    p0Vect = np.log(p0Num / p1Denom)
    # 返回属于侮辱类的条件概率
    return p0Vect, p1Vect, pAbusive

if __name__=='__main__':
    postingList,classVec=loadDataSet()

    myVocabList=createVocabList(postingList)
    print('myVocabList:\n',myVocabList)

    trainMat=[]
    for postinDoc in postingList:
        trainMat.append(setOfWords2Vec(myVocabList,postinDoc))

    p0V,p1V,pAb=trainNB0(trainMat,classVec)
    print('p0V:\n',p0V)
    print('p1V:\n', p1V)
    print('classVec:\n', classVec)
    print('pAb:\n', pAb)

结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R83l4hdJ-1664345103075)(//img-blog.csdn.net/20180314171334539?watermark/2/text/Ly9ibG9nLmNzZG4ubmV0L2ppYW95YW5nd20=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)]

此时已经不存在零概率了。

对classifyNB进行修改:

import numpy as np
from functools import reduce
"""
函数说明:创建实验样本

Parameters:
    无
Returns:
    postingList:实验样本切分的词条
    classVec:类别标签向量
Modify:
    2018-03-14

"""


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']]
    # 类别标签向量,1代表侮辱性词汇,0代表不是
    classVec = [0, 1, 0, 1, 0, 1]
    return postingList, classVec


"""
函数说明:更加vocabList词汇表,将inputSet向量化,向量的每个元素为1或0

Parameters:
    vocabList:createVocabList返回的列表
    inputSet:切分的词条列表
Returns:
    returnVec:文档向量,词集模型
Modify:
    2018-03-14

"""


def setOfWords2Vec(vocabList, inputSet):
    # 创建一个其中所含元素都为0的向量
    returnVec = [0] * len(vocabList)
    # 遍历每个词条
    for word in inputSet:
        # 如果词条存在于词汇表中,则置1
        if word in vocabList:
            returnVec[vocabList.index(word)] = 1
        else:
            print("the word: %s is not in my Vocabulary!" % word)
    # 返回向量文档
    return returnVec


""""
函数说明:将切分的实验样本词条整理成不重复的词条列表,也就是词汇表

Parameters:
    dataSet:整理的样本数据集
Returns:
    vocabSet:返回不重复的词条列表,也就是词汇表
Modify:
    2018-03-14

"""


def createVocabList(dataSet):
    # 创建一个空的不重复列表
    vocabSet = set([])
    for document in dataSet:
        # 取并集
        vocabSet = vocabSet | set(document)
    return list(vocabSet)


"""
函数说明:朴素贝叶斯分类器训练函数

Parameters:
    trainMatrix:训练文档矩阵,即setOfWords2Vec返回的returnVec构成的矩阵
    trainCategory:训练类别标签向量,即loadDataSet返回的classVec
Returns:
    p0Vect:侮辱类的条件概率数组
    p1Vect:非侮辱类的条件概率数组
    pAbusive:文档属于侮辱类的概率
Modify:
    2018-03-14

"""


def trainNB0(trainMtrix, trainCategory):
    # 计算训练的文档数目
    numTrainDocs = len(trainMtrix)
    # 计算每篇文章的词条数
    numWords = len(trainMtrix[0])
    # 文档属于侮辱类的概率
    pAbusive = sum(trainCategory) / float(numTrainDocs)
    # 创建numpy.ones数组,词条初始化为1,拉普拉斯平滑
    p0Num = np.ones(numWords);
    p1Num = np.ones(numWords)
    # 分母初始化为2.0,拉普拉斯平滑
    p0Denom = 2.0
    p1Denom = 2.0

    for i in range(numTrainDocs):
        # 统计属于侮辱类的条件概率所需的数据,即P(w0|1),P(w1|1),P(w2|1)···
        if trainCategory[i] == 1:
            p1Num += trainMtrix[i]
            p1Denom += sum(trainMtrix[i])
        # 统计属于非侮辱类的条件概率所需的数据,即P(w0|0),P(w1|0),P(w2|0)···
        else:
            p0Num += trainMtrix[i]
            p0Denom += sum(trainMtrix[i])
    # 相除
    p1Vect = np.log(p1Num / p1Denom)
    p0Vect = np.log(p0Num / p1Denom)
    # 返回属于侮辱类的条件概率
    return p0Vect, p1Vect, pAbusive

"""
函数说明:朴素贝叶斯分类器分类函数

Parameters:
    vec2Classifyaaa:待分类的词条数组
    p0Vec:侮辱类的条件概率数组
    p1Vec:非侮辱类的条件概率数组
    pClass1:文档属于侮辱类的概率
Returns:
    0 :属于非侮辱类
    1 :属于侮辱类
Modify:
    2018-03-14
"""
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
    #对应元素相乘,logA*B=logA+logB,所以要加上np.log(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

"""
函数说明:测试朴素贝叶斯分类器

Parameters:
    无
Returns:
    无
Modify:
    2018-03-14
"""
def testingNB():
    #创建实验样本
    listOPosts,listClasses=loadDataSet()
    #创建词汇表
    myVocabList=createVocabList((listOPosts))

    trainMat=[]
    for postinDoc in listOPosts:
        #将实验样本向量化
        trainMat.append(setOfWords2Vec(myVocabList,postinDoc))
    #训练朴素贝叶斯分类器
    p0V,p1V,pAb=trainNB0(np.array(trainMat),np.array(listClasses))
    #测试样本1
    testEntry=['love','my','dalmation']
    #测试样本向量化
    thisDoc=np.array(setOfWords2Vec(myVocabList,testEntry))
    #执行分类并打印分类结果
    if classifyNB(thisDoc,p0V,p1V,pAb):
        print(testEntry,'属于侮辱类')
    # 执行分类并打印分类结果
    else:
        print(testEntry,'属于非侮辱类')
    #测试样本2
    testEntry=['stupid','garbage']

    #测试样本向量化
    thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
    # 执行分类并打印分类结果
    if classifyNB(thisDoc, p0V, p1V, pAb):
        print(testEntry, '属于侮辱类')
        # 执行分类并打印分类结果
    else:
        print(testEntry, '属于非侮辱类')

if __name__ == '__main__':
    testingNB()

4.5 朴素贝叶斯——过滤垃圾邮件

朴素贝叶斯的最著名的应用——电子邮件垃圾过滤

步骤:

  • 收集数据:提供文本文件。
  • 准备数据:将文本文件解析成词条向量。
  • 分析数据:检查词条确保解析的正确性。
  • 训练算法:使用我们之前建立的trainNB0()函数。
  • 测试算法:使用classifyNB(),并构建一个新的测试函数来计算文档集的错误率。
  • 使用算法:构建一个完整的程序对一组文档进行分类,将错分的文档输出到屏幕上。

4.5.1 收集数据

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

####4.5.2 准备数据

对于英文文本,我们可以以非字母、非数字作为符号进行切分,使用split函数即可。编写代码如下:

import re

"""
函数说明:接收一个大字符串并将其解析为字符串列表

Parameters:
    无
Returns:
    无
Modify:
    2018-03-14
"""
def textParse(bigString):
    # 将特殊符号作为切分标志进行字符串切分,即非字母、非数字
    listOfTokens = re.split(r'\W*', bigString)
    # 除了单个字母,例如大写的I,其它单词变成小写
    return [tok.lower() for tok in listOfTokens if len(tok) > 2]

"""
函数说明:将切分的实验样本词条整理成不重复的词条列表,也就是词汇表

Parameters:
    dataSet - 整理的样本数据集
Returns:
    vocabSet - 返回不重复的词条列表,也就是词汇表
Modify:
    2018-03-14
"""
def createVocabList(dataSet):
    # 创建一个空的不重复列表
    vocabSet = set([])
    for document in dataSet:
        # 取并集
        vocabSet = vocabSet | set(document)
    return list(vocabSet)

if __name__ == '__main__':
    docList = []; classList = []
    # 遍历25个txt文件
    for i in range(1, 26):
        # 读取每个垃圾邮件,并字符串转换成字符串列表
        wordList = textParse(open('spam/%d.txt' % i, 'r').read())
        docList.append(wordList)
        # 标记垃圾邮件,1表示垃圾文件
        classList.append(1)
        # 读取每个非垃圾邮件,并字符串转换成字符串列表
        wordList = textParse(open('ham/%d.txt' % i, 'r').read())
        docList.append(wordList)
        # 标记非垃圾邮件,1表示垃圾文件
        classList.append(0)
        # 创建词汇表,不重复
    vocabList = createVocabList(docList)
    print(vocabList)

根据词汇表,可以将每个文本向量化,此处将数据集分为训练集和测试集,使用交叉验证的方式测试朴素贝叶斯分类器的准确性,代码如下:

import numpy as np
import re
import random

"""
函数说明:创建实验样本

Parameters:
    无
Returns:
    postingList:实验样本切分的词条
    classVec:类别标签向量
Modify:
    2018-03-14

"""


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']]
    # 类别标签向量,1代表侮辱性词汇,0代表不是
    classVec = [0, 1, 0, 1, 0, 1]
    return postingList, classVec


"""
函数说明:更加vocabList词汇表,将inputSet向量化,向量的每个元素为1或0

Parameters:
    vocabList:createVocabList返回的列表
    inputSet:切分的词条列表
Returns:
    returnVec:文档向量,词集模型
Modify:
    2018-03-14

"""


def setOfWords2Vec(vocabList, inputSet):
    # 创建一个其中所含元素都为0的向量
    returnVec = [0] * len(vocabList)
    # 遍历每个词条
    for word in inputSet:
        # 如果词条存在于词汇表中,则置1
        if word in vocabList:
            returnVec[vocabList.index(word)] = 1
        else:
            print("the word: %s is not in my Vocabulary!" % word)
    # 返回向量文档
    return returnVec


""""
函数说明:将切分的实验样本词条整理成不重复的词条列表,也就是词汇表

Parameters:
    dataSet:整理的样本数据集
Returns:
    vocabSet:返回不重复的词条列表,也就是词汇表
Modify:
    2018-03-14

"""


def createVocabList(dataSet):
    # 创建一个空的不重复列表
    vocabSet = set([])
    for document in dataSet:
        # 取并集
        vocabSet = vocabSet | set(document)
    return list(vocabSet)


"""
函数说明:根据vocabList词汇表,构建词袋模型

Parameters:
    vocabList - createVocabList返回的列表
    inputSet - 切分的词条列表
Returns:
    returnVec - 文档向量,词袋模型

Modify:
    2018-03-14

"""


def bagOfWords2VecMN(vocabList, inputSet):
    # 创建一个其中所含元素都为0的向量
    returnVec = [0] * len(vocabList)
    # 遍历每个词条
    for word in inputSet:
        # 如果词条存在于词汇表中,则计数加一
        if word in vocabList:
            returnVec[vocabList.index(word)] += 1
    # 返回词袋模型
    return returnVec


"""
函数说明:朴素贝叶斯分类器训练函数

Parameters:
    trainMatrix:训练文档矩阵,即setOfWords2Vec返回的returnVec构成的矩阵
    trainCategory:训练类别标签向量,即loadDataSet返回的classVec
Returns:
    p0Vect:侮辱类的条件概率数组
    p1Vect:非侮辱类的条件概率数组
    pAbusive:文档属于侮辱类的概率
Modify:
    2018-03-14

"""


def trainNB0(trainMtrix, trainCategory):
    # 计算训练的文档数目
    numTrainDocs = len(trainMtrix)
    # 计算每篇文章的词条数
    numWords = len(trainMtrix[0])
    # 文档属于侮辱类的概率
    pAbusive = sum(trainCategory) / float(numTrainDocs)
    # 创建numpy.ones数组,词条初始化为1,拉普拉斯平滑
    p0Num = np.ones(numWords);
    p1Num = np.ones(numWords)
    # 分母初始化为2.0,拉普拉斯平滑
    p0Denom = 2.0
    p1Denom = 2.0

    for i in range(numTrainDocs):
        # 统计属于侮辱类的条件概率所需的数据,即P(w0|1),P(w1|1),P(w2|1)···
        if trainCategory[i] == 1:
            p1Num += trainMtrix[i]
            p1Denom += sum(trainMtrix[i])
        # 统计属于非侮辱类的条件概率所需的数据,即P(w0|0),P(w1|0),P(w2|0)···
        else:
            p0Num += trainMtrix[i]
            p0Denom += sum(trainMtrix[i])
    # 相除
    p1Vect = np.log(p1Num / p1Denom)
    p0Vect = np.log(p0Num / p1Denom)
    # 返回属于侮辱类的条件概率
    return p0Vect, p1Vect, pAbusive


"""
函数说明:朴素贝叶斯分类器分类函数

Parameters:
    vec2Classifyaaa:待分类的词条数组
    p0Vec:侮辱类的条件概率数组
    p1Vec:非侮辱类的条件概率数组
    pClass1:文档属于侮辱类的概率
Returns:
    0 :属于非侮辱类
    1 :属于侮辱类
Modify:
    2018-03-14
"""


def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
    # 对应元素相乘,logA*B=logA+logB,所以要加上np.log(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


"""
函数说明:接收一个大字符串并将其解析为字符串列表

Parameters:
    无
Returns:
    无
Modify:
    2018-03-14
"""


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


"""
函数说明:测试朴素贝叶斯分类器

Parameters:
    无
Returns:
    无
Modify:
    2018-03-14

"""


def spamTest():
    docList = []
    classList = []
    fullText = []
    # 遍历25个txt文件
    for i in range(1, 26):
        # 读取每个垃圾邮件,并字符串转换成字符串列表
        wordList = textParse(open('spam/%d.txt' % i, 'r').read())
        docList.append(wordList)
        fullText.append(wordList)
        # 标记非垃圾邮件,1表示垃圾邮件
        classList.append(1)
        # 读取每个非垃圾邮件,并字符串转换为字符串列表
        wordList = textParse(open('spam/%d.txt' % i, 'r').read())
        docList.append(wordList)
        fullText.append(wordList)
        # 标记非垃圾邮件,1表示垃圾邮件
        classList.append(0)
    # 创建词汇表,不重复
    vocabList = createVocabList(docList)
    # 创建存储训练集的索引值的列表和测试集的索引值的列表
    trainingSet = list(range(50));
    testSet = []
    # 从50个邮件中,随机挑选出40个作为训练集,10个做测试集
    for i in range(10):
        # 随机选取索索引值
        randIndex = int(random.uniform(0, len(trainingSet)))
        # 添加测试集的索引值
        testSet.append(trainingSet[randIndex])
        # 在训练集列表中删除添加到测试集的索引值
        del (trainingSet[randIndex])
    # 创建训练集矩阵和训练集类别标签系向量
    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])
        # 如果分类错误,错误计数加1
        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()

函数spamTest()会输出在10封随机选择的电子邮件上的分类错误概率。既然这些电子邮件是随机选择的,所以每次的输出结果可能有些差别。如果发现错误的话,函数会输出错误的文档的此表,这样就可以了解到底是哪篇文档发生了错误。如果想要更好地估计错误率,那么就应该将上述过程重复多次,比如说10次,然后求平均值。相比之下,将垃圾邮件误判为正常邮件要比将正常邮件归为垃圾邮件好。

4.6 朴素贝叶斯——新浪新闻分类(sklearn)

4.6.1 中文语句切分

可以直接使用第三方分词组件,即jieba,也就是”结巴”。

在anaconda prompt中输入:

pip install jieba

即可直接安装。

官方教程:https://github.com/fxsjy/jieba

中文教程:https://www.oschina.net/p/jieba

切分中文语句代码:

"""
函数说明:切分中文语句

"""
import os
import jieba

def TextProcessing(folder_path):
    #查看folder_path下的文件
    folder_list=os.listdir(folder_path)
    #训练集
    data_list=[]
    class_list=[]

    #遍历每个子文件夹
    for folder in folder_list:
        #根据子文件夹,生成新的路径
        new_folder_path=os.path.join(folder_path,folder)
        #存放子文件夹下的txt文件的列表
        files=os.listdir(new_folder_path)

        j=1
        #遍历每个txt文件
        for file in files:
            #每类txt样本数最多100个
            if j>100:
                break
            #打开txt文件
            with open(os.path.join(new_folder_path,file),'r',encoding='utf-8') as f:
                raw=f.read()

            #精简模式,返回一个可迭代的generator
            word_cut=jieba.cut(raw,cut_all=False)
            #generator转换为list
            word_list=list(word_cut)

            data_list.append(word_list)
            class_list.append(folder)
            j+=1
        print(data_list)
        print(class_list)

if __name__=='__main__':
    #文本预处理
    #训练集存放地址
    folder_path='E:\python\machine learning in action\My Code\chap 04\SogouC\Sample'
    TextProcessing((folder_path))


4.6.2 文本特征选择

我们将所有文本分成训练集和测试集,并对训练集中的所有单词进行词频统计,并按降序排序。也就是将出现次数多的词语在前,出现次数少的词语在后进行排序。编写代码如下:

"""
函数说明:切分中文语句

"""
import os
import jieba
import random

def TextProcessing(folder_path,test_size = 0.2):
    #查看folder_path下的文件
    folder_list=os.listdir(folder_path)
    #训练集
    data_list=[]
    class_list=[]

    #遍历每个子文件夹
    for folder in folder_list:
        #根据子文件夹,生成新的路径
        new_folder_path=os.path.join(folder_path,folder)
        #存放子文件夹下的txt文件的列表
        files=os.listdir(new_folder_path)

        j=1
        #遍历每个txt文件
        for file in files:
            #每类txt样本数最多100个
            if j>100:
                break
            #打开txt文件
            with open(os.path.join(new_folder_path,file),'r',encoding='utf-8') as f:
                raw=f.read()
            #精简模式,返回一个可迭代的generator
            word_cut=jieba.cut(raw,cut_all=False)
            #generator转换为list
            word_list=list(word_cut)

            data_list.append(word_list)
            class_list.append(folder)
            j+=1
        #zip压缩合并,将数据与标签对应压缩
        data_class_list=list(zip(data_list,class_list))
        #将data_class_list乱序
        random.shuffle(data_class_list)
        #训练集与测试集切分的索引值
        index=int(len(data_class_list)*test_size)+1
        #训练集
        train_list=data_class_list[index:]
        #测试集
        test_list=data_class_list[:index]
        #训练集解压缩
        train_data_list,train_class_list=zip(*train_list)
        #测试集解压缩
        test_data_list,test_class_list=zip(*test_list)
        #统计训练集词频
        all_words_dict={}
        for word_list in train_data_list:
            for word in word_list:
                if word in all_words_dict.keys():
                    all_words_dict[word]+=1
                else:
                    all_words_dict[word]=1

        #根据键值倒序排列
        all_words_tuple_list=sorted(all_words_dict.items(),key=lambda
            f:f[1],reverse=True)
        #解压缩
        all_words_list,all_words_nums=zip(*all_words_tuple_list)
        #转换成列表
        all_words_list=list(all_words_list)
        return all_words_list,train_data_list,test_data_list,train_class_list,\
               test_class_list

if __name__=='__main__':
    #文本预处理,训练集存放的地址
    folder_path='E:\python\machine learning in action\My Code\chap 04\SogouC\Sample'
    all_words_list, train_data_list, test_data_list, train_class_list, \
    test_class_list=TextProcessing(folder_path,test_size=0.2)
    print(all_words_list)

输出的all_word_list就是将所有训练集的切分结果按照词频降序排列构成的单词集合,前面包含了很多标点符号,和“是”、“的”、“在”等词语,及数字。所以要将这些去掉。

去掉的规则:去掉高频词,至于去掉多少,则根据高频词个数和最终检测率的关系来确定。

如何去掉:可以使用已经整理好的stopwords_cn.txt文本

可以根据这个文档来去掉高频词,不作为分类的特征,首先去除100个,代码如下:

"""
函数说明:切分中文语句

"""
import os
import jieba
import random

def TextProcessing(folder_path,test_size = 0.2):
    #查看folder_path下的文件
    folder_list=os.listdir(folder_path)
    #训练集
    data_list=[]
    class_list=[]

    #遍历每个子文件夹
    for folder in folder_list:
        #根据子文件夹,生成新的路径
        new_folder_path=os.path.join(folder_path,folder)
        #存放子文件夹下的txt文件的列表
        files=os.listdir(new_folder_path)

        j=1
        #遍历每个txt文件
        for file in files:
            #每类txt样本数最多100个
            if j>100:
                break
            #打开txt文件
            with open(os.path.join(new_folder_path,file),'r',encoding='utf-8') as f:
                raw=f.read()
            #精简模式,返回一个可迭代的generator
            word_cut=jieba.cut(raw,cut_all=False)
            #generator转换为list
            word_list=list(word_cut)

            data_list.append(word_list)
            class_list.append(folder)
            j+=1
        #zip压缩合并,将数据与标签对应压缩
        data_class_list=list(zip(data_list,class_list))
        #将data_class_list乱序
        random.shuffle(data_class_list)
        #训练集与测试集切分的索引值
        index=int(len(data_class_list)*test_size)+1
        #训练集
        train_list=data_class_list[index:]
        #测试集
        test_list=data_class_list[:index]
        #训练集解压缩
        train_data_list,train_class_list=zip(*train_list)
        #测试集解压缩
        test_data_list,test_class_list=zip(*test_list)
        #统计训练集词频
        all_words_dict={}
        for word_list in train_data_list:
            for word in word_list:
                if word in all_words_dict.keys():
                    all_words_dict[word]+=1
                else:
                    all_words_dict[word]=1

        #根据键值倒序排列
        all_words_tuple_list=sorted(all_words_dict.items(),key=lambda
            f:f[1],reverse=True)
        #解压缩
        all_words_list,all_words_nums=zip(*all_words_tuple_list)
        #转换成列表
        all_words_list=list(all_words_list)
        return all_words_list,train_data_list,test_data_list,train_class_list,\
               test_class_list

"""
函数说明:读取文件中的内容并去重

Parameters:
    words_file:文件路径
Returns:
    word_set:读取内容的set集合
Modify:
    2018-03-15

"""
def MakeWordSet(words_file):
    #创建set集合
    words_set=set()
    #打开文件
    with open(words_file,'r',encoding='utf-8') as f:
        #一行一行读取
        for line in f.readlines():
            #去回车
            word=line.strip()
            #有文本,则添加到word_set中
            if len(word)>0:
                words_set.add(word)
    #返回处理结果
    return words_set

"""
函数说明:文本特征提取
Parameters:
    all_words_list - 训练集所有文本列表
    deleteN - 删除词频最高的deleteN个词
    stopwords_set - 指定的结束语
Returns:
    feature_words - 特征集
Modify:
    2018-03-15
"""
def words_dict(all_words_list,deleteN,stopWords_set=set()):
    #特征列表
    feature_words=[]
    n=1
    for t in range(deleteN,len(all_words_list),1):
        #feature_words额维度为1000
        if n>1000:
            break
        #如果这个词不是数字,且不是指定的结束语,并且单词长度大于1小于5,那么这个词就可以作为特征词
        if not all_words_list[t].isdigit() and all_words_list[t] not in stopWords_set \
                and 1<len(all_words_list[t])<5:
            feature_words.append(all_words_list[t])
        n+=1
    return feature_words

if __name__=='__main__':
    #文本预处理,训练集存放的地址
    folder_path='E:\python\machine learning in action\My Code\chap 04\SogouC\Sample'
    all_words_list, train_data_list, test_data_list, train_class_list, \
    test_class_list=TextProcessing(folder_path,test_size=0.2)

    #生成stopwords_set
    stopwords_file='stopwords_cn.txt'
    stopwords_set=MakeWordSet(stopwords_file)

    feature_words=words_dict(all_words_list,100,stopwords_set)
    print(feature_words)

从结果可以看出,我们已经滤除了那些没有用的词组,这些feature_words就是我们最终选出用于新闻分类的特征,随后就可以根据特征词将文本向量化,然后用于训练朴素贝叶斯分类器。

4.7 使用sklearn构建朴素贝叶斯分类器

官方文档

scikit-learn中,一共有3个朴素贝叶斯的分类算法类。分别是GaussianNBMultinomialNBBernoulliNB

  • GaussianNB就是先验为高斯分布的朴素贝叶斯;
  • MultinomialNB就是先验为多项式分布的朴素贝叶斯;
  • BernoulliNB就是先验为伯努利分布的朴素贝叶斯。

前面所讲的的先验概率模型就是先验概率为多项式分布的朴素贝叶斯。

对于新闻的分类,属于多分类问题,可以使用MultinomialNB来完成,假设特征的先验概率为多项式分布:

class sklearn.naive_bayes.MultinomialNB(alpha=1.0, fit_prior=True, class_prior=None)
  • alpha:浮点型可选参数,默认为1.0,其实就是添加拉普拉斯平滑,即为上述公式中的λ ,如果这个参数设置为0,就是不添加平滑;
  • fit_prior:布尔型可选参数,默认为True。布尔参数fit_prior表示是否要考虑先验概率,如果是false,则所有的样本类别输出都有相同的类别先验概率。否则可以自己用第三个参数class_prior输入先验概率,或者不输入第三个参数class_prior让MultinomialNB自己从训练集样本来计算先验概率,此时的先验概率为P(Y=Ck)=mk/m。其中m为训练集样本总数量,mk为输出为第k类别的训练集样本数。
  • class_prior:可选参数,默认为None。
fit_prior class_prior 最终先验概率
False 无意义 P ( Y = C k ) = 1 / k P(Y=C_k)=1/k P(Y=Ck)=1/k
True 不填 P ( Y = C k ) = m k / m P(Y=C_k)=mk/m P(Y=Ck)=mk/m
True P ( Y = C k ) = c l a s s _ p r i o r P(Y=C_k)=class\_prior P(Y=Ck)=class_prior

拟合:

fit:一般的拟合

partial_fit:一般用在训练集数据量非常大,一次不能全部载入内存的时候,这个时候可以把训练集分成若干等分,重复调用该方法来一步步学习训练集。

预测:

predict:常用的预测方法,直接给出测试集的预测类别输出

predict_log_proba:预测出的各个类别对数概率里的最大值对应的类别,也就是predict方法得到类别

predict_proba:它会给出测试集样本在各个类别上预测的概率,预测出的各个类别概率里的最大值对应的类别,也就是predict方法得到类别。

确定要去掉的前deleteN个高频词的个数与最终检测准确率的关系,确定deleteN的取值:

"""
函数说明:切分中文语句

"""
import os
import jieba
import random
from sklearn.naive_bayes import MultinomialNB
import matplotlib.pyplot as plt


def TextProcessing(folder_path,test_size = 0.2):
    #查看folder_path下的文件
    folder_list=os.listdir(folder_path)
    #训练集
    data_list=[]
    class_list=[]

    #遍历每个子文件夹
    for folder in folder_list:
        #根据子文件夹,生成新的路径
        new_folder_path=os.path.join(folder_path,folder)
        #存放子文件夹下的txt文件的列表
        files=os.listdir(new_folder_path)

        j=1
        #遍历每个txt文件
        for file in files:
            #每类txt样本数最多100个
            if j>100:
                break
            #打开txt文件
            with open(os.path.join(new_folder_path,file),'r',encoding='utf-8') as f:
                raw=f.read()
            #精简模式,返回一个可迭代的generator
            word_cut=jieba.cut(raw,cut_all=False)
            #generator转换为list
            word_list=list(word_cut)

            data_list.append(word_list)
            class_list.append(folder)
            j+=1
        #zip压缩合并,将数据与标签对应压缩
        data_class_list=list(zip(data_list,class_list))
        #将data_class_list乱序
        random.shuffle(data_class_list)
        #训练集与测试集切分的索引值
        index=int(len(data_class_list)*test_size)+1
        #训练集
        train_list=data_class_list[index:]
        #测试集
        test_list=data_class_list[:index]
        #训练集解压缩
        train_data_list,train_class_list=zip(*train_list)
        #测试集解压缩
        test_data_list,test_class_list=zip(*test_list)
        #统计训练集词频
        all_words_dict={}
        for word_list in train_data_list:
            for word in word_list:
                if word in all_words_dict.keys():
                    all_words_dict[word]+=1
                else:
                    all_words_dict[word]=1

        #根据键值倒序排列
        all_words_tuple_list=sorted(all_words_dict.items(),key=lambda
            f:f[1],reverse=True)
        #解压缩
        all_words_list,all_words_nums=zip(*all_words_tuple_list)
        #转换成列表
        all_words_list=list(all_words_list)
        return all_words_list,train_data_list,test_data_list,train_class_list,\
               test_class_list

"""
函数说明:读取文件中的内容并去重

Parameters:
    words_file:文件路径
Returns:
    word_set:读取内容的set集合
Modify:
    2018-03-15

"""
def MakeWordSet(words_file):
    #创建set集合
    words_set=set()
    #打开文件
    with open(words_file,'r',encoding='utf-8') as f:
        #一行一行读取
        for line in f.readlines():
            #去回车
            word=line.strip()
            #有文本,则添加到word_set中
            if len(word)>0:
                words_set.add(word)
    #返回处理结果
    return words_set

def TextFeatures(train_data_list, test_data_list, feature_words):
    # 出现在特征集中,则置1
    def text_features(text, feature_words):
        text_words = set(text)
        features = [1 if word in text_words else 0 for word in feature_words]
        return features
    train_feature_list = [text_features(text, feature_words) for text in train_data_list]
    test_feature_list = [text_features(text, feature_words) for text in test_data_list]
    # 返回结果
    return train_feature_list, test_feature_list


"""
函数说明:文本特征提取
Parameters:
    all_words_list - 训练集所有文本列表
    deleteN - 删除词频最高的deleteN个词
    stopwords_set - 指定的结束语
Returns:
    feature_words - 特征集
Modify:
    2018-03-15
"""
def words_dict(all_words_list,deleteN,stopWords_set=set()):
    #特征列表
    feature_words=[]
    n=1
    for t in range(deleteN,len(all_words_list),1):
        #feature_words额维度为1000
        if n>1000:
            break
        #如果这个词不是数字,且不是指定的结束语,并且单词长度大于1小于5,那么这个词就可以作为特征词
        if not all_words_list[t].isdigit() and all_words_list[t] not in stopWords_set \
                and 1<len(all_words_list[t])<5:
            feature_words.append(all_words_list[t])
        n+=1
    return feature_words

"""
函数说明:新闻分类器

parameters:
    train_feature_list - 训练集向量化的特征文本
    test_feature_list - 测试集向量化的特征文本
    train_class_list - 训练集分类标签
    test_class_list - 测试集分类标签
Returns:
    test_accuracy - 分类器精度
Modify:
    2018-03-15
"""
def TextClassifier(train_feature_list,test_feature_list,train_class_list,test_class_list):
    classifier=MultinomialNB().fit(train_feature_list,train_class_list)
    test_accuracy=classifier.score(test_feature_list,test_class_list)
    return test_accuracy

if __name__=='__main__':
    #文本预处理,训练集存放的地址
    folder_path='E:\python\machine learning in action\My Code\chap 04\SogouC\Sample'
    all_words_list, train_data_list, test_data_list, train_class_list, \
         test_class_list=TextProcessing(folder_path,test_size=0.2)

    #生成stopwords_set
    stopwords_file='stopwords_cn.txt'
    stopwords_set=MakeWordSet(stopwords_file)

    test_accuracy_list=[]
    deleteNs=range(0,1000,20)
    for deleteN in deleteNs:
        feature_words=words_dict(all_words_list,deleteN,stopwords_set)
        train_feature_list,test_feature_list=TextFeatures(train_data_list,
                                                        test_data_list,feature_words)
        test_accuracy=TextClassifier(train_feature_list,test_feature_list,
                                     train_class_list,test_class_list)
        test_accuracy_list.append(test_accuracy)


    plt.figure()
    plt.plot(deleteNs,test_accuracy_list)
    plt.title('Relationship of deleteNs and test_accuracy')
    plt.xlabel('deleteNs')
    plt.ylabel('test_accuracy')
    plt.show()

将代码修改如下:

if __name__ == '__main__':
    #文本预处理
    folder_path = './SogouC/Sample'                #训练集存放地址
    all_words_list, train_data_list, test_data_list, train_class_list, test_class_list = TextProcessing(folder_path, test_size=0.2)

    # 生成stopwords_set
    stopwords_file = './stopwords_cn.txt'
    stopwords_set = MakeWordsSet(stopwords_file)


    test_accuracy_list = []
    feature_words = words_dict(all_words_list, 450, stopwords_set)
    train_feature_list, test_feature_list = TextFeatures(train_data_list, test_data_list, feature_words)
    test_accuracy = TextClassifier(train_feature_list, test_feature_list, train_class_list, test_class_list)
    test_accuracy_list.append(test_accuracy)
    ave = lambda c: sum(c) / len(c)

4.7 总结

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

【机器学习实战】4、基于概率论的分类方法:朴素贝叶斯 的相关文章

  • 《机器学习实战》源码和数据集的下载

    机器学习实战 这本书对于我们了解机器学习原理和代码实现提供了很大的帮助 xff0c 源码和数据集可在其英文版的官方网站进行下载 xff1a https www manning com books machine learning in ac
  • 【机器学习实战 Task1】 (KNN)k近邻算法的应用

    1 背景 1 1 k近邻算法的概述 xff08 1 xff09 k近邻算法的简介 k 近邻算法是属于一个非常有效且易于掌握的机器学习算法 xff0c 简单的说就是采用测量不同特征值之间距离的方法对数据进行分类的一个算法 xff08 2 xf
  • 预测数值型数据:回归源码分析(1)

    回归模型比较简单 这里先简单介绍下 后面遇到难点再具体分析 回归的一般方法 1 收集数据 采用任意方法收集数据 2 准备数据 回归需要数值型数据 标称型数据将被转成二值型数据 3 分析数据 绘出数据的可视化二维图将有助于对数据做出理解和分析
  • 机器学习实战:AdaBoost预测病马率

    import numpy as np 函数说明 加载数据集 Parameters filename 文件名 Returns dataMat 数据集 labelMat 标签 def loadDataSet filename numFeat l
  • 【机器学习实战】9、利用K-means算法对未标注数据分组

    文章目录 10 1 K 均值聚类算法 10 2 使用后处理来提高聚类性能 10 3 二分K 均值算法 10 4 总结 簇识别 簇识别给出了聚类结果的含义 假定有一些数据 簇识别会告诉我们这些簇到底都是些什么 聚类与分类的区别 分类的目标事先
  • sns.relplot

    介绍采用sns的强大的绘图 可以绘制不止二维的信息 优美的排版 用散点图关联变量 用线强调连续性 聚合和表示不确定性 用语义映射绘制数据子集 显示与facet的多个关系
  • scala机器学习实战(一) 保险数据预测分析

    scala机器学习之保险数据预测分析 数据资料来源 此文章数据内容来源于Scala Machine Learning Projects 2018版 一书 本书分为是一个章节 本文章内容来自于第一章节 书本链接 Scala Machine L
  • 加州房价预测项目详细笔记(Regression)——(2)采样(数据分割)<重要>

    参考内容 机器学习实战 原作者github https github com ageron handson ml 加州房价预测项目精细解释https blog csdn net jiaoyangwm article details 8167
  • 【机器学习实战】11、利用SVD简化数据

    文章目录 14 1 1 隐形语义索引 14 1 2 推荐系统 14 2 矩阵分解 SVD矩阵分解 14 3 利用python实现SVD 14 4 1 相似度计算 14 4 2 基于物品的相似度还是基于用户的相似度 14 4 3 推荐引擎的评
  • Python机器学习从零开始(三)数据准备

    目录 1 数据预处理 1 1调整数据尺度 1 2正态化数据 1 3标准化数据 1 4二值数据 2 数据特征选定 2 1单变量特征选定 2 2递归特征消除 2 3数据降维 2 4特征重要性 总结 特征选择时困难耗时的 也需要对需求的理解和专业
  • AttributeError: module 'random' has no attribute 'rand

    问题 在跟着 机器学习实战 这本书练习的时候 遇到AttributeError module random has no attribute rand的问题 1 出现如下的报错 2 原因 后来发现当时为了方便能够知道自己 py文件是主要练习
  • 【机器学习实战】1、机器学习主要任务

    文章目录 1 1 何谓机器学习 1 2 机器学习重要性 1 3 机器学习主要任务 1 4 如何选择合适的算法 1 5 开发机器学习应用程序的步骤 1 6 python语言的优势 1 6 1 python语言特色 1 6 2 python语言
  • 【机器学习实战】5、Logistic 回归

    文章目录 5 1 基于Logistic回归和Sigmoid函数的分类 5 2 基于最优化方法的最佳回归系数确定 5 2 1 梯度上升法 5 3 python实战 5 3 1 查看数据集分布情况 5 3 2 训练 5 3 3 绘制决策边界 5
  • 【机器学习实战】8、预测数值型数据:回归

    文章目录 8 1 用线性回归找到最佳拟合直线 8 1 1 线性回归 8 1 2数据可视化 8 1 3 求回归系数向量 并根据系数绘制回归曲线 8 2 局部加权线性回归 LWLR 8 3 预测鲍鱼年龄 8 4 岭回归 8 5 前向逐步回归 8
  • 【机器学习实战】4、基于概率论的分类方法:朴素贝叶斯

    文章目录 4 1 基于贝叶斯决策理论的分类方法 4 1 1 贝叶斯决策理论 4 1 2 条件概率 4 1 3 全概率公式 4 1 4 贝叶斯推断 4 1 5 朴素贝叶斯 4 2 使用朴素贝叶斯进行文档分类 4 3 总结 4 4 朴素贝叶斯改
  • Python机器学习从零开始(一)序章

    目录 前言 写在前面 1 什么是机器学习 1 1 监督学习 1 2无监督学习 2 Python中的机器学习 3 必须环境安装 Anacodna安装 总结 前言 每一次变革都由技术驱动 纵观人类历史 上古时代 人类从采集狩猎社会 进化为农业社
  • 机器学习实战:逻辑回归(3)-Sklearn实现病马死亡率预测

    from sklearn linear model import LogisticRegression 函数说明 使用Sklearn构建Logistic回归分类器 Parameters 无 Returns 无 def colicSklear
  • 机器学习:python 实现一个linear regression

    1 原理介绍 linear regression步骤 1 导入数据 2 将数据分为训练集合测试集 linear regression 分为x train x text y train y test 3 导入线性回归算法 利用训练集计算出模型
  • 代码注释:机器学习实战第8章 预测数值型数据:回归

    写在开头的话 在学习 机器学习实战 的过程中发现书中很多代码并没有注释 这对新入门的同学是一个挑战 特此贴出我对代码做出的注释 仅供参考 欢迎指正 coding gbk from numpy import 作用 从文件中导入数据 输入 文件
  • Python机器学习从零开始(五)算法审查

    目录 1 审查分类算法 1 1线性算法审查 1 2非线性算法审查 2 审查回归算法 2 1线性算法审查 2 2非线性算法审查 3 算法比较 总结 程序测试是展现BUG存在的有效方式 但令人绝望的是它不足以展现其缺位 艾兹格 迪杰斯特拉 Ed

随机推荐

  • Linux--进程间通信、IPC、管道

    目录 1 进程间通信的方法 2 IPC机制 1 有命管道 1 简介 5 管道的特点 6 循环写读 2 无名管道 1 简介 2 代码 4 总体特点 5 管道实现图 1 进程间通信的方法 1 管道 2 信号量 3 共享内存 4 消息队列 5 套
  • java - jdwp远程调试线协议的使用

    前言 线上服务器出现的bug 因为各种复杂环境的原因 经常会很难在本地调试 只能到处打log 然后去服务器查看log日志 以定位问题产生原因 是否一工具能像idea中本地debug一样能直接断点调试呢 介绍 JDWP Java Debug
  • 华为上机考试注意事项及编程技巧(精品)

    这是一篇关于华为招聘软件类职位上机考试的博客 主要介绍一下华为机考的流程 注意事项以及一些机试题中常用的编程技巧 写得有点长 但都是尽心尽力敲的 如果真的要参加华为招聘 或者类似公司的招聘 建议稍微花点时间看完 话不多说 直接进入正题 一
  • 我对维度建模和范式建模的一点理解

    谈维度建模和范式建模之前 先了解下模型设计的三个阶段吧 概念模型 将业务划分成几个主题 逻辑模型 定义各种实体 属性 关系 物理模型 设计数据对象的物理实现 比如表的命名规范 字段的命名规范 字段类型等 一 范式建模 我先来介绍一下范式 范
  • 思维的特点和缺陷

    人类总是喜欢歌颂自己的大脑 比如 思想的威力 逻辑的威力 数学的威力 数学来自于思考 科学的威力 科学来源于思考 还有 意识 这个 人类与动物最大的区别 i blah blah 不过 几乎没有人关心过这种想法究竟来自于人体的哪个器官 心理学
  • 海思3559 安装

    设置地址 开机后任意键 进入 u boot 界面显示 hisilicon 以下内容转自 海思开发记录 一 3559A开发环境搭建 whitefish520的博客 CSDN博客 海思3559a 说明 这次安装的是Ubuntu14 04 64位
  • java8 lambda 获取list对象中重复数据

    工作上的场景 简单记录一下 在这里直接借用业务上的list 不再new 了 List
  • 前台模糊查询中用“\%”替换字符串中的“%”

    最近在做电商项目 前端开发好后就丢给我们 用的时候发现一个缺陷 前台模糊查询的时候 输入一个 或者包含 的词 查询的时候不准确 解决过程中第一个问题 前端用了Js的 decodeURL 转码 将前台输入的 转码了 无法传到后台 参考 htt
  • Java前端知识HTML

    Java前端知识 首先我们用的是HBuilderX软件 当然 前端知识有很多 如果有遗忘或者需要查询的可以去菜鸟驿站查询 比较全 html的文档结构主要是有三部分组成的 1 标记用于html文件的最前面 用来表示html文件的开始 而的标记
  • QSignalMapper信号映射器的使用

    目录 QSignalMapper介绍 Signal 信号 slots 根据标识获取对象 给对象设置标识 删除映射 实例 代码 需求升级 总结 相关文章 QSignalMapper介绍 该类收集一组无参数的信号 并使用与发送信号的对象对应的整
  • 不限时长,免费制作

    在这个信息爆炸的时代 短视频已经崭露头角 成为人们获取信息 娱乐和学习的首选渠道 事实上 大部分互联网用户每天都沉浸在短视频的世界中 这无疑证明了短视频营销的巨大潜力和不可替代的地位 2023年的数据进一步印证了这一点 中国短视频用户规模已
  • 页面禁止长按保存图片和长按复制文字

    1 禁止长按保存图片 img pointer events none 禁止none 启用auto Tips pointer events属性详解 官方文档 https www html cn book css properties user
  • 面试题 01.06. 字符串压缩

    字符串压缩 利用字符重复出现的次数 编写一种方法 实现基本的字符串压缩功能 比如 字符串aabcccccaaa会变为a2b1c5a3 若 压缩 后的字符串没有变短 则返回原先的字符串 你可以假设字符串中只包含大小写英文字母 a至z 示例1
  • 找出数组中的最大有序子数组

    效率O n m import java util HashSet import java util Set public class FindLongestArray public static void main String args
  • 第十四届蓝桥杯单片机第二场模拟赛程序(AD+字符接受串口)

    完整代码 include
  • MIPI介绍(CSI DSI接口)

    MIPI Mobile Industry Processor Interface 是2003年由ARM Nokia ST TI等公司成立的一个联盟 目的是把手机内部的接口如摄像头 显示屏接口 射频 基带接口等标准化 从而减少手机设计的复杂程
  • 解决“AD中设置板子区域时候遇到的找不到闭合形状”问题

    问题说明 今天给大家分享一下 我们在画PCB时候有时候会想将PCB设置区域改为自己板子的大小 就是整个区域就只有自己的板子 大家不明白的话 可以看看下面这张图 或许就明白了 对于如何将PCB区域改为我们板子的形状 可以参考我这篇文章 这里我
  • web3j的基础用法-3ETH交易监听器

    ETH的交易监听器 demo简单实现了4种 监听区块 public Subscription subscribeBlock final Action1
  • 玩客云armbian刷机教程

    文章作者 GoodBoyboy 文章链接 https blog goodboyboy top posts 3292274545 html 版权声明 本博客所有文章除特别声明外 均采用 CC BY NC SA 4 0 许可协议 转载请注明来自
  • 【机器学习实战】4、基于概率论的分类方法:朴素贝叶斯

    文章目录 4 1 基于贝叶斯决策理论的分类方法 4 1 1 贝叶斯决策理论 4 1 2 条件概率 4 1 3 全概率公式 4 1 4 贝叶斯推断 4 1 5 朴素贝叶斯 4 2 使用朴素贝叶斯进行文档分类 4 3 总结 4 4 朴素贝叶斯改