Skip to content

Latest commit

 

History

History
135 lines (117 loc) · 7.16 KB

朴素贝叶斯.md

File metadata and controls

135 lines (117 loc) · 7.16 KB

朴素贝叶斯(分类)

一、概率论--条件概率

关于条件概率计算,全概率公式,及贝叶斯定理,之前写的统计学笔记有很详细介绍: 《深入浅出统计学》笔记 P(A|B)=P(B|A)P(A)/P(B)

二、使用朴素贝叶斯进行垃圾邮件识别

应用场景

文档分类:目前有两类txt文件,一类被标记为垃圾邮件,另一类被标记为正常邮件。以这些数据为训练集,训练模型,进而来预测判断其他txt是否是垃圾邮件.

基本原理

算法思路

  1. 读取数据集中所有的txt文档(去除标点符号,只读取单词),每个txt文档的内容对应一个wordList,定义一个docList用来保存所有的wordList。 docList=[wordList1,wordList2……wordListn]
  2. 用一个列表fullText来存放训练集中所有文档中的所有单词,去重。
  3. 随机构建训练集和测试集。
  4. 把每一个txt文档转换成数学模型,便与训练。(wordList,fullText,主要利用这两个列表来进行转换)
  5. 对训练集的数学模型进行训练。主要计算“所有垃圾邮件中每个单词占总垃圾邮件单词的比例(概率)”,“所有正常邮件中每个单词占总正常邮件单词的比例(概率)”,“训练集中垃圾邮件的概率”
  6. 对测试集进行测试。

代码实现

import numpy as np
import re
import warnings
import random
warnings.filterwarnings('ignore')
from math import log

def classifyNB(vec2Classify, p0Vect, p1Vect, pAbusive):
    # 所有正常邮件中每个单词占总正常邮件单词的比例(概率)  p0Vect
    # 所有垃圾邮件中每个单词占总垃圾邮件单词的比例(概率)  p1Vect
    # 训练集中垃圾邮件的概率                              pAbusive
    p1 = sum(vec2Classify * p1Vect) + log(pAbusive)    #element-wise mult
    p0 = sum(vec2Classify * p0Vect) + log(1.0 - pAbusive)
    if p1 > p0:
        return 1
    else: 
        return 0


def trainNB0(trainMat,trainClasses):
    numTrainDocs = len(trainMat)                          # 训练集总数(邮件总数)
    numWords = len(trainMat[0])                           # 所有邮件包含的单词word总数(不重复)
    # sum(trainClasses)表示训练集中垃圾邮件的总数
    # float(numTrainDocs) 表示训练集中邮件总数
    pAbusive = sum(trainClasses)/float(numTrainDocs)      # 训练集中垃圾邮件的概率     
    p0Num = np.ones(numWords)                             # 统计所有正常邮件每个单词出现的次数array
    p1Num = np.ones(numWords)                             # 统计所有垃圾邮件每个单词出现的次数array
    p0Denom = 2.0                                         # 统计所有正常邮件的总单词个数,实数
    p1Denom = 2.0                                         # 统计所有垃圾邮件的总单词个数,实数
    for i in range(numTrainDocs):
        # 0表示正常邮件 1表示垃圾邮件
        if trainClasses[i] == 1:
            p1Num += trainMat[i]
            p1Denom += sum(trainMat[i])
        else:
            p0Num += trainMat[i]
            p0Denom += sum(trainMat[i])

    p1Vect = np.log(p1Num/p1Denom)                       # 所有垃圾邮件中每个单词占总垃圾邮件单词的比例(概率)
    p0Vect = np.log(p0Num/p0Denom)                       # 所有正常邮件中每个单词占总正常邮件单词的比例(概率)

    return (p0Vect,p1Vect,pAbusive)


def txtWords2Vec(single_word_list, inputSet):
    returnVec = [0]*len(single_word_list)
    for word in inputSet:
        if word in single_word_list:
            returnVec[single_word_list.index(word)] += 1
    return returnVec


def textParse(text):
    word_list = re.split(r'\W*',text)         # 根据标点符号去切割文本
    return [word.lower() for word in word_list if len(word)>2]


def main():
    docList = []        # 存放每一个邮件里面的内容
    classList = []      # 存放每一个邮件的类别(正常邮件/垃圾邮件)
    fullText = []       # 存放所有邮件内容
    single_word_list = []# 统计所有邮件内的所有单词,不重复
    for i in range(1,22):
        wordList = textParse(open(r'E:\code\jupyter_notebook\email\ham\%d.txt' % i, 'r').read())
        docList.append(wordList)
        fullText.extend(wordList)
        classList.append(0)    # 0表示正常邮件

        wordList = textParse(open(r'E:\code\jupyter_notebook\email\spam\%d.txt' % i, 'r').read())
        docList.append(wordList)
        fullText.extend(wordList)
        classList.append(1)    # 1表示垃圾邮件
    single_word_list = list(set(fullText))

    # 一共有n个邮件,从这n个邮件里随机选择m个作为测试集,其他的作为训练集
    print(len(docList))                   
    trainingSet = list(range(40))
    testSet=[]           
    for i in range(10):
        # random.uniform(x,y)生成指定范围内的随机实数
        randIndex = int(random.uniform(0,len(trainingSet)))
        testSet.append(trainingSet[randIndex])
        del(trainingSet[randIndex])  

    trainMat=[]
    trainClasses = []
    for docIndex in trainingSet:
        # 把每一个邮件转换成向量的数学模型
        # 如[0,0,1,1,4,2,0,0],每个数字代表该位置的单词word,在这个邮件中出现的次数
        txt_vec = txtWords2Vec(single_word_list, docList[docIndex])
        trainMat.append(txt_vec)        
        trainClasses.append(classList[docIndex])

    # 对训练集进行训练
    tuple_p = trainNB0(np.array(trainMat),np.array(trainClasses))
    p0Vect = tuple_p[0]                             # 所有正常邮件中每个单词占总正常邮件单词的比例(概率)
    p1Vect = tuple_p[1]                             # 所有垃圾邮件中每个单词占总垃圾邮件单词的比例(概率)
    pAbusive = tuple_p[2]                           # 训练集中垃圾邮件的概率  
    print(pAbusive)
    errorCount = 0
    for docIndex in testSet:        
        wordVector = txtWords2Vec(single_word_list, docList[docIndex])
        predict_result = classifyNB(np.array(wordVector),p0Vect,p1Vect,pAbusive)    # 预测的结果
        real_result = classList[docIndex]                                           # 真实结果
        print('预测结果%s,真实结果%s' % (predict_result,real_result))
        if predict_result != real_result:
            print('预测错的邮件:',docIndex)
            errorCount += 1
    print('预测错了%s个' % errorCount)

if __name__=='__main__':
    main()

结果