机器学习 朴素贝叶斯分类食品安全新闻

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

这次实验将学习利用朴素贝叶斯方法对垃圾邮件,食品安全新闻进行分类。


提示:以下是本篇文章正文内容,下面案例可供参考


一、预备知识

1.基本概念

先验概率:根据以往经验和分析得到的某事情发生的概率,比如厦门下雨的概率可以通过以往的经验或者统计结果得到,我们用P(Y)来表示在没有训练数据前假设Y拥有的初始概率。

后验概率:根据已经发生的事件来分析得到的概率,以P(Y|X)代表假设X成立的情况下观察到Y的概率,因为它反映了在看到训练数据XY成立的置信度。

条件概率:事情A发生时事件B发生的概率,即P(B|A);后验概率就是一种条件概率,但是与其他条件的不同之处在于,后验概率限定了目标事件为隐变量取值,而其中的条件为观测结果。一般的条件概率,条件和事件都可以是任意的。贝叶斯就是用先验概率估计后验概率。

联合概率:联合概率是指在多元的概率分布中多个随机变量分别满足各自条件的概率。X与Y的联合概率表示为P(X,Y)P(XY)P(X∩Y)

假设X和Y都服从正态分布,那么P(X<5,Y<0)就是一个联合概率,表示X<5,Y<0两个条件同时成立的概率,表示两个事件共同发生的概率。

2.贝叶斯公式

 设A表示事件,B表示A发生的影响因素,则:

P(A)为先验概率,即事件A发生不用考虑影响因素B;P(A|B)为后验概率,表示在因素B的条件下A发生的概率;P(B|A)为条件概率,表示事件A发生的条件下因素B发生的概率;P(B)为归一化因子,这里B是已知的,相当于一个常量,不影响其他概率。用图形表示如下:

P(A|B)即上图中橙色部分(联合概率)占红色部分的比例,贝叶斯公式推导:

        

总结:后验概率 = 先验概率 * 条件概率




二、朴素贝叶斯原理

1.判别模型和生成模型

监督学习方法又分为生成式方法判别式方法,所学到的模型分别称为生成式模型判别式模型。

生成式模型:由训练数据学习联合概率分布P(X,Y),然后求得后验概率分布P(Y|X)。具体来说,利用训练数据学习P(X|Y)和P(Y)的估计,得到联合概率分布:P(C,Y)=P(Y)*P(Y|X),再利用它进行分类。经典算法:朴素贝叶斯、K近邻、HMM、深度信念网络(DBN)等。

判别式模型:由数据直接学习决策函数Y=f(X)或者条件概率分布作为预测的模型,即判别模型。基本思想是有限样本条件下建立判别函数,不关心背后的数据分布,关心的是对于给定的输入,应该预测什么样的输出。经典算法:线性回归、Logistic回归、决策树、支持向量机等。

举例如下:

利用两种模型来确定一只羊是山羊还是绵羊?

生成式模型:首先根据山羊的特征学习出一个山羊的模型,然后根据绵羊的特征学习出一个绵羊的模型,然后从这只羊中提取特征,放到山羊模型中看概率是多少,再放到绵羊模型中看概率是多少,哪个概率大就属于哪一类。

判别式模型:直接从山羊和绵羊的数据中提取特征x并学习得到模型,然后从待分类的羊中提取特征x,将其代入到模型中以判断这只羊是山羊和绵羊的概率。

我们可以看到,生成式模型强调数据本身特点,判别式模型强调数据边界。在分类的过程中,生成式模型对每个结果都要亲自试一试,遍历完一遍后取概率最大的结果;而判别式模型直接通过模型得到结果。

2.贝叶斯分类器

2.1 贝叶斯准则

贝叶斯准则告诉我们如何交换条件概率中的条件与结果,即如果已知P(X|C),要求P(C|X),那么可以使用下面的计算方法:

 2.2 贝叶斯分类器

假设现在我们有一组训练样本,以及与其相对应的分类标签。每个元组都被表示为n维属性向量属性向量的形式,一共由K个类别C1,C2,...,Ck,分类要做的就是模型可以预测数据属于哪个类别。对于每个类别Ci,利用贝叶斯公式来估计在给定训练元组X时的条件概率P(Ci|x)。

当且仅当概率P(Ci|x)在所有类别中取值最大时,数据x属于类Ci。P(Ci)是类先验概率,P(x|Ci)是样本x相对于类Ci的类条件概率,称为似然。因为P(x)是用于归一化的证据因子,其对于所有的类别都是恒定的。所以只需要基于训练数据来估计P ( ci ) 和P(x∣ci​)。

贝叶斯分类器存在的问题:

(1)对于类条件概率P ( x∣ci )来说,由于它涉及关于x所有属性的联合概率,直接根据样本出现的频率来估计会遇到严重的困难,因为如果假设样本的d个属性都是二值的,则样本空间可能会有 种可能性。在现实中,这个值往往远大于训练样本数m,也就是说很多样本的取值可能在训练样本中可能根本没有出现,由于未被观测到和没有出现是两个不同的事件,所以直接根据样本频率来估计P ( x ∣ c i )显然是不可行的。

(2)由统计学知,如果每个特征需要N个样本,那么对于10个特征就需要个样本,1000个特征的词汇表将需要个样本。可以看到,所需样本数会随着特征数目增大而迅速增长。如果特征之间相互独立,那么样本数就可以从减少到1000 ∗ N。

 3.朴素贝叶斯分类器

我们可以发现基于贝叶斯公式来计算后验概率P(c∣x)的主要困难在于类条件概率 P(x∣c)是所有属性上的联合概率,难以从有限的训练样本中直接估计而得。为了避开这个障碍,朴素贝叶斯分类器采用了属性条件独立性假设,即对于已知类别所有属性独立的对分类结果产生影响,也就是说所有属性都是条件独立的,联合概率就等于每个单独属性概率的乘积:

 

 因为分母对于所有的类别都是一样的,所以我们的目标就是:最大后验概率(CMP)

 朴素贝叶斯分类器的训练过程就是基于训练数据集D来计算类先验概率 P(ci) 和类条件概率。

 3.1 特征属性的条件概率估计的计算

令Dc表示训练集D中第c类样本组合的集合,则类先验概率:

 对连续属性,假定其符合标准正态分布,然后用标准正态分布的概率密度函数求解。

3.2 拉普拉斯修正

需要注意的是,若某个属性值在训练集中在某个类中没有出现过,则类条件概率会等于零,导致累乘计算出的概率值为零。为了避免这个问题,在计算概率值时要进行平滑处理,常用拉普拉斯修正,避免因训练样本不充足导致概率估值为零的问题,对每个特征的出现数初始化为1,分母初始化为2。在训练集充分大时,修正过程所引入的影响也会变得可忽略,使得估计值逐渐趋向于实际概率。

3.3 防溢出策略

在条件概率乘法计算过程中,因子一般较小(均是小于的实数)。当属性数量增多时,会导致累乘结果下溢出现象。在代数中有ln(a*b) = ln(a)+ln(b)因此可以把条件概率累乘转换成对数累加。分类结果仅需对比概率的对数假发运算后的值,以确定划分的类别。

4.测试朴素贝叶斯分类器

利用25封侮辱性邮件和25封非侮辱性文件对朴素贝叶斯分类器进行测试,其中49封作为训练数据,随机抽取10个作为测试集:

4.1 构建词向量

'''
函数说明:创建实验样本
:return: 进行词条切分后的文档集合;类别标签的集合(侮辱性和非侮辱性)
'''
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表示侮辱性文字,0代表正常言论
    return postingList,classVec

#创建一个包含在所有文档中出现的不重复词的列表
def createVocabList(dataSet):
    vocabSet = set([])                      #创建空的集合
    for document in dataSet:
        vocabSet = vocabSet | set(document) #求两个集合的并集
    return list(vocabSet)

#根据vocabList词汇表,将每个inputSet词条向量化,向量的每个值为1或0,分别表示该词有或者没有出现在词汇表中
#输入变量:词汇表,某个文档
def setOfWords2Vec(vocabList, inputSet):
    #创建一个其中所含元素都为0的向量
    returnVec = [0]*len(vocabList)
    for word in inputSet:
        if word in vocabList:
            returnVec[vocabList.index(word)] = 1
        else:
            print("the word: %s is not in my Vocabulary!" % word)
    return returnVec

#朴素贝叶斯词袋模型
def bagOfWords2VecMN(vocabList, inputSet):
    returnVec = [0]*len(vocabList)
    for word in inputSet:
        if word in vocabList:
            #每个词在词袋中可以出现多次。出现则累加
            returnVec[vocabList.index(word)] += 1
    return returnVec

4.2 朴素贝叶斯分类训练函数

#朴素贝叶斯分类器训练函数
'''
函数说明:朴素贝叶斯分类器训练函数
:param trainMatrix: 文档矩阵
:param trainCategory: 文档类别标签向量
:return: 非侮辱类的条件概率数组,侮辱类的条件概率数组,文档属于侮辱类的概率
'''
def trainNB0(trainMatrix,trainCategory):
    numTrainDocs = len(trainMatrix)                   #训练集的数量,如6个元素
    #print("数量为:",numTrainDocs)
    numWords = len(trainMatrix[0])                    #每个词条向量的长度,如每一个都是32维
    #print("长度为:", numWords)
    #sum(trainCategory)表示将标签向量中的(0,1)相加,即得到1的个数(也就是侮辱性文档数目)
    #标签中“1”表示侮辱,“0”表示非侮辱,所以是统计文档属于侮辱类的概率
    pAbusive = sum(trainCategory)/float(numTrainDocs)

    #zeros()创建的数组,其元素值均为0
    #p0Num = zeros(numWords)
    #p1Num = zeros(numWords)
    #p0Denom = 0.0
    #p1Denom = 0.0

    #ones()函数可以创建任意维度和元素个数的数组,其元素值均为1
    #创建numpy.ones数组,词条出现数初始化为1,拉普拉斯平滑方法(为了防止与0相乘)
    p0Num = ones(numWords)
    p1Num = ones(numWords)
    #分母初始化为2,拉普拉斯平滑方法
    p0Denom = 2.0
    p1Denom = 2.0
    for i in range(numTrainDocs):
        if trainCategory[i] ==1:
            #统计属于侮辱类的条件概率所需的数据,即P(w0/1),P(w1/1)......
            p1Num += trainMatrix[i]            #数组相加
            #print("p1Num:",p1Num)
            p1Denom += sum(trainMatrix[i])     #sum():将trainMatrix[i]中所有元素相加
            #print("p1Denom:",p1Denom)
        else:
            #统计属于非侮辱类的条件概率所需的数据,即P(w0/0),P(w1/0)......
            p0Num += trainMatrix[i]
            p0Denom +=sum(trainMatrix[i])
            #print("p0Denom:",p0Denom)
    p1Vect = log(p1Num/p1Denom)             #p1Num中的每一项取对数
    p0Vect = log(p0Num/p0Denom)             #非侮辱性邮件中单词出现的概率
    return p0Vect,p1Vect,pAbusive


 4.3 分类函数

#朴素贝叶斯分类函数
'''
函数说明:朴素贝叶斯分类函数
:param vec2Classify: 要分类的向量
:param p0Vec: 非侮辱类的条件概率数组
:param p1Vec: 侮辱类的条件概率数组
:param pClass1: 文档属于侮辱类的概率
:return: 0->表示非侮辱类文档;1->表示侮辱类文档
'''
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
    #两个向量对应元素相乘,然后求和
    p1 = sum(vec2Classify * p1Vec) +log(pClass1)
    p0 = sum(vec2Classify * p0Vec) +log(1-pClass1)
    if p1>p0:
        return 1
    else:
        return 0

 4.4 测试函数

#利用单条数据测试
def testingNB():
    listOPosts,listClasses = loadDataSet()
    # 创建一个包含在所有文档中出现的不重复词的列表
    myVocabList = createVocabList(listOPosts)
    trainMat=[]
    for postinDoc in listOPosts:
        trainMat.append(setOfWords2Vec(myVocabList,postinDoc))
    p0V,p1V,pAb = trainNB0(array(trainMat),array(listClasses))
    testEntry=['love','my','dalmation']
    thisDoc = array(setOfWords2Vec(myVocabList,testEntry))
    print(testEntry,'分类结果为:',classifyNB(thisDoc,p0V,p1V,pAb))
    testEntry = ['stupid','garbage']
    thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
    print(testEntry, '分类结果为:', classifyNB(thisDoc, p0V, p1V, pAb))

#文件解析函数
def textParse(bigString):           #input is big string, #output is word list
    import re                       #正则表达式工具
    #分割数据,其分隔符是除单词、数字外任意的字符串
    listOfTokens = re.split(r'\W*', bigString)
    #单词全部转小写,过滤没用的短字符串
    return [tok.lower() for tok in listOfTokens if len(tok) > 2]
#垃圾邮件测试函数
def spamTest():
    docList = []           #存放每个邮件的单词向量
    classList = []         #存放邮件对应的标签
    fullText = []
    for i in range(1, 26):
        #读取侮辱类(spam中存储)邮件,并生成单词向量
        wordList = textParse(open('./email/spam/%d.txt' % i).read())
        docList.append(wordList)               #将单词向量存放到docList中
        fullText.extend(wordList)
        classList.append(1)                    #存放对应的类标签,侮辱类为1
        # 读取非侮辱类(ham中存储)邮件,并生成单词向量
        wordList = textParse(open('./email/ham/%d.txt' % i).read())
        docList.append(wordList)               #将单词向量存放到docList中
        fullText.extend(wordList)
        classList.append(0)                    #存放对应的类标签,非侮辱类为0
    #由所有的单词向量生成词库
    # xx = len(docList)
    # yy = list(range(xx))
    # print(xx,yy)
    vocabList = createVocabList(docList)
    trainSet = list(range(50))                      #产生0-49的50个数字
    testIndex = []                                  #存放测试数据的下标
    for i in range(10):
        #从0-49之间随机生成一个下标
        randIndex = int(random.uniform(0, len(trainSet)))
        testIndex.append(trainSet[randIndex])  #提取对应的数据作为测试数据
        del(trainSet[randIndex])              #删除对应的数据,避免下次再选中
    trainDataSet = []                          #存放训练数据(用于词集方法)
    trainClasses = []                          #存放训练数据标签(用于词集方法)
    trainDataSet1 = []                        #存放训练数据(用于词袋方法)
    trainClasses1 = []                        #存放训练数据标签(用于词袋方法)
    for docIndex in trainSet:
        #提取训练数据(词集方法)
        trainDataSet.append(setOfWords2Vec(vocabList, docList[docIndex]))
        #提取训练数据标签
        trainClasses.append(classList[docIndex])

        #提取训练数据(词袋方法)
        trainDataSet1.append(bagOfWords2VecMN(vocabList, docList[docIndex]))
        trainClasses1.append(classList[docIndex])
    #开始训练
    p0V, p1V, pSpam = trainNB0(array(trainDataSet), array(trainClasses))
    errorCount = 0                     #统计测试时分类错误的数据个数
    p0V_1, p1V_1, pSpam1 = trainNB0(array(trainDataSet1), array(trainClasses1))
    errorCount1 = 0
    #开始测试分类器
    for Index in testIndex:  # classify the remaining items
        #print("classification:", Index)
        wordVector = setOfWords2Vec(vocabList, docList[Index])   #数据预处理
        # 测试分类器,如果分类不正确,错误个数加1
        if classifyNB(array(wordVector), p0V, p1V, pSpam) != classList[Index]:
            errorCount += 1
        wordVector1 = bagOfWords2VecMN(vocabList, docList[Index])  #数据预处理
        if classifyNB(array(wordVector1), p0V_1, p1V_1, pSpam1) != classList[Index]:
            errorCount1 += 1
    #输出分类错误率
    print('词集方法(set)的错误率: ', float(errorCount) / len(testIndex))
    print('词库方法(bag)的错误率: ', float(errorCount1) / len(testIndex))

 运行结果:

可见平均错误率高达61%,但是由于训练集和测试集都很小,即使10个测试集中只有一个出错,错误率也会有10%之高,因此这个结果无法正确反映朴素贝叶斯方法分类的准确性。同时还有假设属性条件独立性所带来的误差,所以我们接下来用较多数据集对其进行测试。 

三、朴素贝叶斯分类食品安全新闻

1.数据集

数据集包括两部分,训练数据train_food.txt(3352条)和train_notfood.txt(14946条),测试数据eval_food.txt(600条)和eval_notfood.txt(899条)。

数据集位置:(1条消息) 分类+朴素贝叶斯+食品安全新闻.zip-机器学习文档类资源-CSDN文库

部分数据展示:

2.读取训练集

#1代表食品安全新闻,0代表非食品安全新闻
# 读取数据集
def readData(posFile,negFile):
    docList = []  # 存放训练集
    classList = []  # 存放分类标签

    # 读入类别为"1"的数据集(食品安全相关)
    posList = list(open(posFile,encoding='utf-8').readlines())
    posVec =[1]*len(posList)
    docList += posList
    classList +=posVec
    # 读入类别为"0"的数据集(非食品安全相关的训练集),并生成向量
    negList = list(open(negFile,encoding='utf-8').readlines())
    negVec = [0] * len(negList)
    docList += negList
    classList += negVec
    return docList,classList

3.对新闻进行分词

对这些新闻进行分词,为了节省以后训练使用的时间,将分词的结果保存到训练书同目录下。名字为cleaned_trainMatrix2.txt。

#对新闻进行分词
def jieba_cut_and_save_file(inputList, output_cleaned_file=False):
    """
    1. 读取中文文件并分词句子
    2. 可以将分词后的结果保存到文件
    3. 如果已经存在经过分词的数据文件则直接加载
    """
    output_file = os.path.join('./data/', 'cleaned_' + 'trainMatrix2.txt')
    #如果已经存在经过分词的数据文件则直接加载
    #os.path.exists()检验给出的路径是否真实存在
    if os.path.exists(output_file):
        lines = list(open(output_file, 'r').readlines())
        lines = [line.strip('\n').split(' ') for line in lines]
    else:
        lines = [list(jieba.cut(clean_str(line))) for line in inputList]
        lines = [[word for word in line if word != ' '] for line in lines]
        #如果不存在则保存分词后的文件文件
        if output_cleaned_file:
            with open(output_file, 'w') as f:
                for line in lines:
                    f.write(" ".join(line) + '\n')
    # 由所有的单词向量生成词库
    vocabulary = createVocabList(lines)
    # 根据词典生成词向量化器,并进行词向量化
    setOfWords2Vec = setOfWords2VecFactory(vocabulary)
    vectorized = [setOfWords2Vec(news) for news in lines]
    return vectorized, vocabulary
def clean_str(string):
    """
    1. 将除汉字外的字符转为一个空格
    2. 除去句子前后的空格字符
    """
    string = re.sub(r'[^\u4e00-\u9fff]', ' ', string)
    string = re.sub(r'\s{2,}', ' ', string)
    return string.strip()

 3.生成词典

生成词典,它包含了所有新闻中出现的,但是不重复的词语。

#生成词典
def createVocabList(dataSet):
    """
    从分词后的新闻列表中构造词典
    """
    # 创造一个包含所有新闻中出现的不重复词的列表。
    vocabSet = set([])
    for news in dataSet:
        vocabSet = vocabSet | set(news)
        # |取并
    return list(vocabSet)

4.将分词后的新闻向量化

#测试需要用到的向量化新闻(对单个新闻向量化)
def vectorize_newslist(news_list,vocabulary):
    """
    将新闻列表新闻向量化,变成词向量矩阵
    注:如果没有词典,默认值为从集合中创造
    """
    # 分词与过滤
    cut_news_list = [list(jieba.cut(clean_str(news))) for news in news_list]

    # 根据词典生成词向量化器,并进行词向量化
    setOfWords2Vec = setOfWords2VecFactory(vocabulary)
    vectorized = [setOfWords2Vec(news) for news in cut_news_list]
    return vectorized,vocabulary

#将分此后的新闻向量化
def setOfWords2VecFactory(vocabList):
    """
    通过给定词典,构造该词典对应的setOfWords2Vec
    函数的嵌套定义
    """
    #优化:通过事先构造词语到索引的哈希表,加快转化
    index_map = {}
    #enumerate()函数用于将一个可遍历的数据对象组合为一个索引序列,同时列出数据和数据下标
    for i, word in enumerate(vocabList):
        index_map[word] = i

    def setOfWords2Vec(news):
        """
        以在构造时提供的词典为基准词典向量化一条新闻
        """
        result = [0]*len(vocabList)
        for word in news:
                #通过默认值查询同时起到获得索引与判断有无的作用
                index = index_map.get(word, None)
                if index:
                    result[index] = 1
        return result
    return setOfWords2Vec

5.训练函数和分类函数

这次测试和训练所用数据都很大,每次训练都需要大量时间,因此将训练后的模型保存下来,测试直接导入已保存的模型,节省时间,为了方便保存模型,模型看作一个类。

#将模型看作类,方便模型的保存
class oldNB:
    def __init__(self,vocabulary):
        self.p1V = None
        self.p0V = None
        self.p1 = None
        self.vocabulary = vocabulary

    def train(self,trainMatrix, classVector):
        """
        训练函数
        :param trainMatrix: 训练词向量矩阵
        :param classVector: 分类向量
        """
        # 新闻的数量
        numTrainNews = len(trainMatrix)
        # 训练集中每个词条向量的长度,如每一个都是32维
        numWords = len(trainMatrix[0])

        # 新闻属于食品安全类的概率,先验概率
        pFood = sum(classVector) / float(numTrainNews)
        # 手动设置先验概率
        # pFood = float(1)/float(200)
        # 初始化概率,避免有零的存在使后面乘积结果为0
        p0Num = ones(numWords)
        p1Num = ones(numWords)
        p0Sum = 2.0
        p1Sum = 2.0
        for i in range(numTrainNews):
            if classVector[i] == 1:
                # +=
                # 每条食品安全新闻中,每个词的数量分布,p1Num是一个向量
                p1Num += trainMatrix[i]
                # 求每条新闻出现的食品安全集合中的词语的数量总和,p1Sum表示0类新闻中词语出现总数
                p1Sum += sum(trainMatrix[i])
            else:
                p0Num += trainMatrix[i]
                p0Sum += sum(trainMatrix[i])
        # 在1的情况下每个词语出现的概率
        p1Vect = log(p1Num / p1Sum)
        # 在0的情况下每个词语出现的概率
        p0Vect = log(p0Num / p0Sum)
        #return p1Vect, p0Vect, pFood
        # 保存结果
        self.p0V = p0Vect
        self.p1V = p1Vect
        self.p1 = pFood

    def classify_news(self,news):
        """
        分类函数,对输入新闻进行处理,然后分类
        :param newa: 欲分类的新闻
        """
        vectorized = vectorize_newslist([news],self.vocabulary)
        return self.classify_vector(vectorized)

    def classify_vector(self,vec2Classify):
        """
        分类函数,对输入词向量分类
        :param vec2Classify: 欲分类的词向量
        """
        vec2Classify = vec2Classify[0]
        p1 = sum(vec2Classify * self.p1V) + log(self.p1)
        # 元素相乘
        p0 = sum(vec2Classify * self.p0V) + log(1.0 - self.p1)
        if p1 > p0:
            return 1
        else:
            return 0

6.训练模型

#训练模型
def trainModal():
    posFile = "./data/train_food.txt"
    negFile = "./data/train_notfood.txt"

    print("正在获取训练矩阵及其分类向量")
    #保存训练数据集列表,分类标签
    trainList, classVec = readData(posFile, negFile)

    trainMat =[]
    trainClass = []         #类别标签列表
    trainClass += classVec

    #global vocabulary       # 全局变量,保存词库
    print("正在将训练矩阵分词,并生成词表")
    #对读入的新闻进行分词
    trainMat,vocabulary = jieba_cut_and_save_file(trainList,True)
    # 初始化模型
    bayes = oldNB(vocabulary)
    print("正在训练模型")
    bayes.train(trainMat, trainClass)

    print("保存模型")
    joblib.dump(bayes, "./arguments/train_model.m")

7.测试模型

#测试模型
def testModal():
    posFile1 = "./data/eval_food.txt"
    negFile1 = "./data/eval_notfood.txt"

    print("正在得到测试矩阵及其分类向量")
    trainList1, classVec1 = readData(posFile1, negFile1)

    # 读取模型
    nb = joblib.load("arguments/train_model.m")

    dataLen = range(len(trainList1))
    results = []
    for index in dataLen:
        result = nb.classify_news(trainList1[index])
        results.append(result)
    ans = 0
    sureCount = 0
    for i in range(len(classVec1)):
        if results[i] == classVec1[i]:
            sureCount += 1
    ans = sureCount / len(classVec1)
    print("正确率:" + str(ans))

测试结果:

 可以看到这次测试相较于上面用40条训练,10条测试有了更明显的效果,94%的正确率在分类时还是比较可观的,同时我们还可以根据实际情况手动设置先验概率,使正确率更高。

将先验概率手动设置为1/200时得到如下正确率:

该处使用的url网络请求的数据。




总结

利用朴素贝叶斯方法分类的优点:

(1)非常容易建立,并且能够很快作出决策。当有新增样本数据时,仅对新样本属性值所涉及的概率估值进行修正即可实现增量学习。

(2)计算简单,可处理多类别数据

(3)决策结果很容易解释

(4)常用于文本分类

 缺点:

(1)朴素贝叶斯模型假设属性之间是相互独立的,而这个假设在实际应用中往往并不成立,虽然在属性相关性较小时朴素贝叶斯性能良好,但在属性个数比较多或者属性之间相关性较大时,分类效果不好;

(2)需要知道先验概率,并且先验概率在很多时候是取决于假设,而假设很多时候是不准确的,导致预测结果正确率不高;

(3)对输入数据表达形式很敏感。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值