python 实现垃圾邮件分类(贝叶斯+交叉验证法)

  • 本文目的

    本文将详细介绍用贝叶斯方法和交叉验证法实现垃圾邮件的分类,我将从设计算法框架,再到具体实现详细介绍。理论知识推荐张学工的模式识别(这里不再涉及),或者这篇blog这里写链接内容

  • 算法知识介绍
    贝叶斯的目的时利用先验知识和类概率密度去估计后验概率,python 实现垃圾邮件分类(贝叶斯+交叉验证法)_第1张图片
    如公式所示,算法的目的是通过带标签的样本训练出得到先验概率:p(Ci),和类概率密度p(w/Ci),然后带入带测试数据集进行验证,如果验证集的厚颜概率密度有P(C1/w) > P(C2/w) 那么测试集样本属于C1类反之属于C2类。p(w)为归一化参数,不会影响分类结果。

  • 算法处理的数据:
    spam文件夹:10封txt文档,ham文件夹:10封txt文档。python 实现垃圾邮件分类(贝叶斯+交叉验证法)_第2张图片python 实现垃圾邮件分类(贝叶斯+交叉验证法)_第3张图片

  • 算法处理流程

  • 1-读入ham和spam文件中的文档,切分单词,建立一个无重复单词的单词库,且生成原始数据矩阵,和标签矩阵

  • 2-利用交叉验证法进行训练,(这里为了符合实际会采用拉普拉斯修正),得到每个单词的类概率密度和先验概率

    • 3-带入验证集数据,再训练得到的类概率密度和先验概率下进行验证,判定是否为垃圾邮件

    • 算法实现
      代码框架如下:
      python 实现垃圾邮件分类(贝叶斯+交叉验证法)_第4张图片
      1-首先我们实现第一个框架内容
 trainData = []   #原始数据
    trainLabelInput = []  #标签矩阵
    WordsLib = []         #单词库
    for i in range(1,11):
        wordlist = splitWords(open('E:/C_Code/python/py0527spam/spam/%d.txt'%i).read())
        trainData.append(wordlist)
        WordsLib.extend(wordlist)   #为生成库做准备
        trainLabelInput.append(0)   #垃圾邮件标志为0
        wordlist = splitWords(open('E:/C_Code/python/py0527spam/ham/%d.txt'%i).read())
        trainData.append(wordlist)
        WordsLib.extend(wordlist)
        trainLabelInput.append(1)   #非垃圾邮件标记为1     

    VocabList = createWordsLib(trainData)#生成了一个无重复单词的单词库

这里我们将得到一个没有重复单词的单词库(1350个不重复的单词),生成这个单词库的目的是为了对每一个样本都生成一个1*1350的0矩阵,然后对样本里的单词在单词库中进行检索,如果在单词库中,那么把对应位置的0置为1,即把单词样本转化为了一个代表单词样本的0,1矩阵。我们还把所有的样本加载到了trainData中,其对应的标签加载到了trainLabelInput中。

  • 实现第二个框架里的内容
 testLabels = []
    trainIndex = list(range(20))
    for i in range(5):
        randomNum = int(np.random.uniform(0,len(trainIndex)))
        testLabels.append(trainIndex[randomNum]) #挑选出了测视集
        del(trainIndex[randomNum])           #删除测试集的索引号

    trainMat = []     #训练矩阵
    trainLabel = []   #训练矩阵标签

    for indexNum in trainIndex:#生成了训练矩阵和训练标签
        trainMat.append(createTrainMat(VocabList,trainData[indexNum]))
        trainLabel.append(trainLabelInput[indexNum])

    p0w,p1w,pVa = train(trainMat,trainLabel)  #得到训练数据

这里我们采用交叉验证法,随机的挑选五个样本作为验证集,剩余的15个样本作为训练集。通过训练将得到类概率密度,和先验概率

  • 实现第三个框架里的内容
 errorNum = 0
    for numIndex in testLabels:
        testVec = createTrainMat(VocabList,trainData[numIndex])
        count = predictionResult(testVec,p0w,p1w,pVa)
        print("count:",count)
        print("trainLabelInput[numIndex]:",trainLabelInput[numIndex])

        if count != trainLabelInput[numIndex]:            
            errorNum += 1
            print("numIndex:",numIndex)
            print(trainData[numIndex])
    print("error is",float(errorNum/len(testLabels)))

我们将对验证集的预测值和实际标签进行对比,得到最终的错误率,这里可能你得到的错误率会为0,或者为0.2,或者0.4,也就是说你的验证集的选择不同可能对你的预测是有影响的,因为你可能恰巧在五个验证集中选中了0,1,2个错分类的样本,我这里是在ham文档中人为的加了2个spam文件中的txt文档,所以每次由于选的验证集不同,可能会导致不同的错误率。

完整的代码如下:

import numpy as np




def splitWords(txtString):  #读入txt文件,且对读入的txt文件生成一个单词的list
    import re
    wordList = []
    listOfWords = re.split(r'\W*',txtString)
    for word in listOfWords:
        if(len(word) > 2):
            wordList.append(word)
    return wordList


def createWordsLib(wordslist):
    WordsLib = set([])
    for word in wordslist:
        WordsLib = WordsLib | set(word)   #set() word 是一个列表
    return list(WordsLib)



def createTrainMat(vacabList,trainData):
    Returntrain = np.zeros(len(vacabList))
    for word in trainData:
        if word in vacabList:
            Returntrain[vacabList.index(word)] = 1  #存在某特征(单词),则某处置为1
        else:
            print(word,"is not in vacabList")
    return Returntrain




def train(trainData,trainLabel):
    sampleNum = len(trainData)  #样本数
    trainDataFeatures = len(trainData[0]) #特征数
    pVa = sum(trainLabel) / len(trainLabel)  #先验概率,不是垃圾邮件的先验概率
    p0Num = np.ones(trainDataFeatures)
    p1Num = np.ones(trainDataFeatures)

    for i in range(sampleNum):
        if trainLabel[i] == 0:#如果为垃圾邮件,则求垃圾邮件的类概率密度
            p0Num += trainData[i]
            p0NumSum = sum(trainData[i])
        else:
            p1Num += trainData[i]
            p1NumSum = sum(trainData[i])

    pw0 = np.log(p0Num/p0NumSum)
    pw1 = np.log(p1Num/p1NumSum)

    return pw0,pw1,pVa


def predictionResult(testMat,pw0,pw1,pVa):
    p1 = sum(testMat * pw1) + np.log(pVa)
    p0 = sum(testMat * pw0) + np.log(1-pVa)
    if p1 > p0:
        return 1
    else:
        return 0




def trainThread():


    #原始数据的载入:读入数据,切分,生成一个总汇单词表;同时生成一个原始数据矩阵,和标签矩阵。
    trainData = []   #原始数据
    trainLabelInput = []  #标签矩阵
    WordsLib = []         #单词库
    for i in range(1,11):
        wordlist = splitWords(open('E:/C_Code/python/py0527spam/spam/%d.txt'%i).read())
        trainData.append(wordlist)
        WordsLib.extend(wordlist)   #为生成库做准备
        trainLabelInput.append(0)   #垃圾邮件标志为0
        wordlist = splitWords(open('E:/C_Code/python/py0527spam/ham/%d.txt'%i).read())
        trainData.append(wordlist)
        WordsLib.extend(wordlist)
        trainLabelInput.append(1)   #非垃圾邮件标记为1     

    VocabList = createWordsLib(trainData)#生成了一个无重复单词的单词库



    #利用留存法进行训练,被选的进行训练(随机),未被选的当作测试集,计算出类概率密度,和先验概率

    testLabels = []
    trainIndex = list(range(20))
    for i in range(5):
        randomNum = int(np.random.uniform(0,len(trainIndex)))
        testLabels.append(trainIndex[randomNum]) #挑选出了测视集
        del(trainIndex[randomNum])           #删除测试集的索引号

    trainMat = []     #训练矩阵
    trainLabel = []   #训练矩阵标签

    for indexNum in trainIndex:#生成了训练矩阵和训练标签
        trainMat.append(createTrainMat(VocabList,trainData[indexNum]))
        trainLabel.append(trainLabelInput[indexNum])

    p0w,p1w,pVa = train(trainMat,trainLabel)  #得到训练数据



#    testLabels = []
    #被剔除的的样本进行验证
    errorNum = 0
    for numIndex in testLabels:
        testVec = createTrainMat(VocabList,trainData[numIndex])
        count = predictionResult(testVec,p0w,p1w,pVa)
        print("count:",count)
        print("trainLabelInput[numIndex]:",trainLabelInput[numIndex])

        if count != trainLabelInput[numIndex]:            
            errorNum += 1
            print("numIndex:",numIndex)
            print(trainData[numIndex])
    print("error is",float(errorNum/len(testLabels)))






    #得出概率密度预测准确率

代码中已经详细注释,按照框架阅读,不会再有难度,下面贴出预测的结果:
python 实现垃圾邮件分类(贝叶斯+交叉验证法)_第5张图片
python 实现垃圾邮件分类(贝叶斯+交叉验证法)_第6张图片
python 实现垃圾邮件分类(贝叶斯+交叉验证法)_第7张图片

你可能感兴趣的:(python 实现垃圾邮件分类(贝叶斯+交叉验证法))