关于条件概率计算,全概率公式,及贝叶斯定理,之前写的统计学笔记有很详细介绍: 《深入浅出统计学》笔记 P(A|B)=P(B|A)P(A)/P(B)
文档分类:目前有两类txt文件,一类被标记为垃圾邮件,另一类被标记为正常邮件。以这些数据为训练集,训练模型,进而来预测判断其他txt是否是垃圾邮件.
- 读取数据集中所有的txt文档(去除标点符号,只读取单词),每个txt文档的内容对应一个wordList,定义一个docList用来保存所有的wordList。 docList=[wordList1,wordList2……wordListn]
- 用一个列表fullText来存放训练集中所有文档中的所有单词,去重。
- 随机构建训练集和测试集。
- 把每一个txt文档转换成数学模型,便与训练。(wordList,fullText,主要利用这两个列表来进行转换)
- 对训练集的数学模型进行训练。主要计算“所有垃圾邮件中每个单词占总垃圾邮件单词的比例(概率)”,“所有正常邮件中每个单词占总正常邮件单词的比例(概率)”,“训练集中垃圾邮件的概率”
- 对测试集进行测试。
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()