1.解析并切分文本文件
2.随机构建训练测试集
3.使用贝叶斯分类算法分类
4.验证结果错误率

贝叶斯算法在另一篇文章中注释详细有述
另,该文参照《机器学习实战》,在代码中可能由于版本原因书中正则表达式切分词时有错误,目前未解决
文中有一部分为测试问题的输出函数

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
'''=================================================
@Project -> File   :bayes -> bayesOfEmail
@IDE    :PyCharm
@Author :zgq
@Date   :2021/1/10 20:14
@Desc   :
=================================================='''

import re
from numpy import *
import random


#2、创建一个包含在所有句子中的不重复出现的词列表
def createVocabList(dataSet):
    vocabSet=set([])    #创建一个set变量,她可以去掉重复的词
    for document in dataSet:
        vocabSet=vocabSet | set(document)   #将词条列表输给set构造函数,set就回返回一个不重复的list
    return list(vocabSet)

#3、将输入的一句话转换为词向量(one hot类型)
def setOfWords2Vec(vocabList,inputSet):
    returnVec=[0]*len(vocabList)    #先将这个返回的词向量初始化一个长度为onehot的向量
    for word in inputSet:
        #对于传入这句话的每个单词来判断是否有 有放1没有放o
        if word in vocabList:
            returnVec[vocabList.index(word)]=1
        else:
            print("the word: %s is not in my Vocabulary!" % word)
    return returnVec

#训练算法:从词向量计算概率
def trainNB0(trainMatrix,trainCategory):        #trainMatrix是一个矩阵是一个二维的,每一行是一个样本(由词向量组成的矩阵)
    #此处是上边要传递的不是原先的都是单词的矩阵,而是one hot类型的矩阵
    numTrainDocs=len(trainMatrix)   #len(矩阵)返回行数
    numWords=len(trainMatrix[0])    #trainMatrix返回矩阵一行的长度,即每条样本的属性数(词数)
    pAbusive=sum(trainCategory)/float(numTrainDocs)     #文档属于侮辱性类的概率,第一项为侮辱性类词向量次数、第二行为总样本数
    p0Num=ones(numWords)   #做了一个全为0的向量(0,0,0,0),长度为样本数
    p1Num=ones(numWords)
    p0Denom=2.0         #
    p1Denom=2.0
    for i in range(numTrainDocs):       #遍历文本矩阵每一行,即遍历每一条样本
        if trainCategory[i]==1:
            p1Num=p1Num+trainMatrix[i]  #如果该行种类为1的话,将这行词向量盖上到这个(0,0,0,0,0,0,0) 上去
            #如果这句话是侮辱性的句子,将这句话的里边的所有词都放入P1num中,最后执行完毕后会是一个(3,1,0,11,15……),对应于我的词汇表中每个词出现的次数
            p1Denom=p1Denom+sum(trainMatrix[i]) #加和该句话的总词数
        else:
            p0Num=p0Num+trainMatrix[i]
            p0Denom=p0Denom+sum(trainMatrix[i])

        #在上面的过程中,步骤为对句子构成的词向量构成的矩阵,对每一句话,如果这句话是侮辱性类别的,在我们词表中记录她出现了,出现一次次数加一
        #最后得到的是  p1Num 所有的词在句子为侮辱性的情况下出现的次数。
        #而对于P1Denom,对与每句属于类被1的句子,都将这句话的词数加进去,最后得到了,这个总的 矩阵中,语料中,是侮辱性的词语总数
        #因为 p1Num为一个向量,记录了每个词在所有的侮辱性句子中出现的总次数,将其除以侮辱性句子总词数,获得在c概率下p(w|1)
    p1Vect=log(p1Num/p1Denom)    #词向量除以浮点数,结果为我们的词汇表中每一个词在侮辱性句子下出现的概率
    p0Vect=log(p0Num/p0Denom)
    return p0Vect,p1Vect,pAbusive


#利用词向量概率来构建贝叶斯分类函数
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


#接受一个大字符串并将其解析为字符串列表
def textParse(bigString):
    listOfTokens=re.split(r'\W*',bigString)    #将字符串切分
    return [tok.lower() for tok in listOfTokens if len(tok)>2]   #去掉长度小于2的字符串,且转化为小写

#文件解析及完整的垃圾邮件测试函数
def spamTest():
    docList=[]
    classList=[]
    fullText=[]
    for i in range(1,26):
        wordList=textParse(open('email/spam/%d.txt' % i).read())   #spam是正面的,ham是负面的
        docList.append(wordList)
        fullText.extend(wordList)
        classList.append(1)
        wordList=textParse(open('email/ham/%d.txt' % i).read())
        docList.append(wordList)
        fullText.extend(wordList)
        classList.append(0)

    #解析函数中输出什么?
    print("解析函数中输出的wordlist:")
    print(wordList)
    print("解析函数中输出的docList:")
    print(fullText)
    print("输出classlist")
    print(classList)
    print("测试一下open。read函数")
    test_open=open('email/spam/1.txt').read()
    print(test_open)
    print("测试parse函数")
    print(textParse(test_open))

    print("创建词汇表:")
    vocabList=createVocabList(docList)      #创建不重复的词汇表用于构建one hot 向量

    print("随机选择10个作为测试集放到testSet中,并且将其从trainingSet中删除")#此处选择的只是它的标签(就是它是第几个)而没有选择了本身,最后的选择是一个index【1,5,18,26,3……】
    trainingSet=list(range(50)) #range()函数产生一个从0到50的列表 即trainingSet=[0,1,2,3……,49,50]
    testSet=[]   #训练集为50里面不放回的随机选10个
    for i in range(10):
        randIndex=int(random.uniform(0,len(trainingSet)))   #返回一个从0到len范围的随机数
        testSet.append(trainingSet[randIndex])
        del(trainingSet[randIndex]) #不放回的随机抽取,把当前这个序号抽出来之后,后面就不会抽到她了

    print("对于选为训练集的每一个文本,都将其转化为onehot类型的词向量,最后构成一个矩阵")
    trainMat=[]
    trainClasses=[]
    for docIndex in trainingSet:
        trainMat.append(setOfWords2Vec(vocabList,docList[docIndex]))    #这边的doclist是将邮件刚解析为list后的东西,需要将其转换为此词向量
        trainClasses.append((classList[docIndex])) #将其对应的类别也安排上
    #使用朴素贝叶斯分类器进行分类,此处是求出了两个向量,一个是基于one hot词汇表上每个词对应是好词或者是坏此的概率,最后要用这个概率来求最后的总概率
    p0V,p1V,pSpam=trainNB0(array(trainMat),array(trainClasses))

    #开始使用训练集进行测试
    errorCount=0
    for docIndex in testSet:
        print("测试集",docIndex,":",docList[docIndex])
        wordVector=setOfWords2Vec(vocabList,docList[docIndex])
        print('the right sequence is: %d' %classList[docIndex],'and our predict sequence is: %d' % classifyNB(array(wordVector),p0V,p1V,pSpam))
        if classifyNB(array(wordVector),p0V,p1V,pSpam)!=classList[docIndex]:
            errorCount=errorCount+1
    print('the error rate is:',float(errorCount)/len(testSet))

spamTest()


运行结果

解析函数中输出的wordlist:
[]
解析函数中输出的docList:
[]
输出classlist
[1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0]
测试一下open。read函数
--- Codeine 15mg -- 30 for $203.70 -- VISA Only!!! --
-- Codeine (Methylmorphine) is a narcotic (opioid) pain reliever
-- We have 15mg & 30mg pills -- 30/15mg for $203.70 - 60/15mg for $385.80 - 90/15mg for $562.50 -- VISA Only!!! ---
测试parse函数
[]
创建词汇表:
随机选择10个作为测试集放到testSet中,并且将其从trainingSet中删除
对于选为训练集的每一个文本,都将其转化为onehot类型的词向量,最后构成一个矩阵
测试集 28 : []
the right sequence is: 1 and our predict sequence is: 1
测试集 16 : []
the right sequence is: 1 and our predict sequence is: 1
测试集 25 : []
the right sequence is: 0 and our predict sequence is: 1
测试集 11 : []
the right sequence is: 0 and our predict sequence is: 1
测试集 7 : []
the right sequence is: 0 and our predict sequence is: 1
测试集 9 : []
the right sequence is: 0 and our predict sequence is: 1
测试集 2 : []
the right sequence is: 1 and our predict sequence is: 1
测试集 3 : []
the right sequence is: 0 and our predict sequence is: 1
测试集 47 : []
the right sequence is: 0 and our predict sequence is: 1
测试集 0 : []
the right sequence is: 1 and our predict sequence is: 1
the error rate is: 0.6

定位到正则表达式切分文本出现错误,但是暂时不知道如何解决

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐