朴素贝叶斯
优点: 在数据较少的情况下仍然有效 可以处理多类别问题
缺点:对输入的数据的准备方式较为敏感
适用数据类型:标称型数据
p1(x,y)>p2(x,y) 那么类别是1
p2(x,y)>p1(x,y) 那么类别是2
贝叶斯决策的核心是选择具有最高概率的决策
朴素贝叶斯分类器通常有两种方式 : 伯努利模型 和 多项式模型
这里采用伯努利实现方式 该实现不考虑词在文档中出现的次数 只考虑是否出现
某种意义上相当于假设词是等权重的
from numpy import *
# 词表到向量的转换函数
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|set(document) 两个词汇集合取并集
# 将每篇文章中的新词加入到词汇集
# set集合所有元素不重复
vocabSet = vocabSet|set(document)
# 将词汇集转换为list
return list(vocabSet)
# 词集模型 只考虑单词是否出现
# vocabList:词汇表
# inputSet:某个文档向量
def setofWords2Vec(vocabList,inputSet):
# 创建一个其中所含元素都为0的向量
returnVec = [0]*len(vocabList)
# 输入集合中的词汇如果出现在词汇表中 定影向量位置设置为1
for word in inputSet:
if word in vocabList:
# vocabList.index(word) 找到word所在的索引值
# 因为vocabList是从set集合转换过来所以每次只改变一个0
returnVec[vocabList.index(word)] = 1
else:
print('The word: %s is not in my Vocabulary!'%word)
return returnVec
# 朴素贝叶斯词袋模型
# 每个词是否出现作为一个特征 这可以作为词集模型 伯努利模型
# 如果一个词不仅出现一次 是这个词是否出现不能表达的信息 被称为 词袋模型 多项式模型
# 对setofWords2Vec()进行修改
def bagofWords2VecMN(vocabList, inputSet):
returnVec = [0]*len(vocabList)
for word in inputSet:
if word in inputSet:
# 该词汇出现自动加一
returnVec[vocabList.index(word)] += 1
return returnVec
# 朴素贝叶斯分类器训练函数
# trainMatrix 词向量数据集
# trainCategory 数据集对应的类别标签
# p0Vect:词汇表中各个单词在正常言论中的类条件概率密度
# p1Vect:词汇表中各个单词在侮辱性言论中的类条件概率密度
# pAbusive:侮辱性言论在整个数据集中的比例
def trainNB0(trainMatrix,trainCategory):
# 训练集总条数
numTrainDocs = len(trainMatrix)
# 训练集中的所有不重复单词总数
numWords = len(trainMatrix[0])
# 初始化概率 计算属于侮辱性文档 class = 1 的概率,p(1)
# p(0) = 1-p(1) 二分类 多于两类需要修改
# 侮辱类占总数的比例
pAbusive = sum(trainCategory)/float(numTrainDocs)
# 正常言论的类条件概率密度p(某单词|正常言论)=p0Num/p0Denom
p0Num = zeros(numWords)
# 侮辱性言论的类条件概率密度 p(某单词|侮辱性言论)=p1Num/p1Denom
p1Num = zeros(numWords)
# 初始化分母置为0
p0Denom = 0.0
p1Denom = 0.0
for i in range(numTrainDocs):
# 以下是向量相加
if trainCategory[i] == 1:
# 如果该篇文章是侮辱性的
# 统计侮辱类所有文档中的各个单词总数
p1Num += trainMatrix[i]
# p1Denom侮辱类总单词数
p1Denom += sum(trainMatrix[i])
else:
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
# 词汇表中的单词在侮辱性言论文档中的类条件概率
p1Vect = p1Num/p1Denom
# 词汇表中的单词在正常性言论文档中的类条件概率
p0Vect = p0Num/p0Denom
return p0Vect , p1Vect , pAbusive
# 利用贝叶斯分类器对文档进行分类时,要计算多个概率的乘积以获取某个文档属于某个类别的概率
# 即计算p(w0|1)*p(w1|1)p(w2|1)
# 若其中有一个概率值为0,最后乘积为零 为降低这种影响
# 可以把所有词的出现初始化为1,并将分母初始化为2
# 大部分相乘因子很小,所以程序会下溢出,四舍五入得到0,所以对乘积取自然对数
# ln(a*b) = ln(a)+ln(b) 避免下溢出或者浮点数舍入导致错误 同时采用自然对数不会有任何损失
# 修改trainNB0
def trainNB1(trainMatrix, trainCategory):
numTrainDocs = len(trainMatrix)
numWords = len(trainMatrix[0])
pAbusive = sum(trainCategory) / float(numTrainDocs)
# 修改初试值
p0Num = ones(numWords)
p1Num = ones(numWords)
p0Denom = 2.0
p1Denom = 2.0
for i in range(numTrainDocs):
if trainCategory[i] == 1:
p1Num += trainMatrix[i]
p1Denom += sum(trainMatrix[i])
else:
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
# 取自然对数
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.0 - pClass1)
if p1 > p0:
return 1
else:
return 0
def testingNB():
# 获得训练数据,类别标签
listOPosts, listClasses = loadDataSet()
# 创建词汇表
myVocabList = createVocabList(listOPosts)
# 构建矩阵,存放训练数据
trainMat = []
# 遍历原始数据,转换为词向量,构成数据训练矩阵
for postinDoc in listOPosts:
# 数据转换后存入数据训练矩阵trainMat中
trainMat.append(setofWords2Vec(myVocabList, postinDoc))
# 训练分类器
p0V, p1V, pAb = trainNB1(array(trainMat),array(listClasses))
testEntry = ['love','my','dalmation']
thisDoc = array(setofWords2Vec(myVocabList, testEntry))
print(testEntry, 'classified as: ',classifyNB(thisDoc, p0V, p1V, pAb))
testEntry = ['stupid', 'garbage']
thisDoc = array(setofWords2Vec(myVocabList,testEntry))
print(testEntry, 'classified as: ', classifyNB(thisDoc, p0V, p1V, pAb))
listOPosts , listClasses = loadDataSet()
myVocabList = createVocabList(listOPosts)
# 文件解析及完整的垃圾邮件测试函数
# 1
# print(myVocabList)
# print(setofWords2Vec(myVocabList,listOPosts[0]))
# print(setofWords2Vec(myVocabList,listOPosts[3]))
# 2
# trainMat = []
# for postinDoc in listOPosts:
# trainMat.append(setofWords2Vec(myVocabList, postinDoc))
# p0V, p1V, pAb = trainNBO(trainMat, listClasses)
# print(pAb)
# print(p0V)
# print(p1V)
# 3
testingNB()
# 4
# 使用朴素贝叶斯对电子邮件进行分类
# 准备数据 切分文本
mySent = 'This book is the best book on python or M.L. I have ever laid eyes upon.'
import re
regEx = re.compile('\W')
listOgTokens = regEx.split(mySent)
# 去除空字符串
# list1 = [tok for tok in listOgTokens if len(tok) > 0]
# 去除空字符串同时全部转化为小写
# tok.upper()
# tok.lower()
# list2 = [tok.lower() for tok in listOgTokens if len(tok) > 0]
# print(listOgTokens)
# print(list1)
# print(list2)
# emailText = open('email/ham/6.txt').read()
# listOgTokens = regEx.split(emailText)
# listText = [tok.lower() for tok in listOgTokens if len(tok) > 2]
# print(listText)
# 测试算法 使用朴素贝叶斯进行交叉验证
# 留存交叉验证: 随机选择数据的一部分作为训练集,剩余部分作为测试集的过程
# 文件解析及完整的垃圾函数测试函数
def textParse(bigString):
import re
listOgTokens = re.split(r'\W',bigString)
return [tok.lower() for tok in listOgTokens if len(tok) >2]
def spamTest():
# 词汇列表 1*n列 1维数组
docList = []
# 结果列表 1*n列 1维数组 0:正常 1:垃圾邮件
classList = []
# 二维数组 存放邮件 和结果列表一一对应
fullText = []
# 填充三个列表
for i in range(1,26):
wordList = textParse(open('email/spam/%d.txt'%i).read())
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)
# 词汇列表去重取并集
vocabList = createVocabList(docList)
# 为每封邮件编号
trainingSet = list(range(50))
testSet = []
# 50个邮件随机分成2组,一组10个,一组40个 用于测试和训练
for i in range(10):
# 随机选取10个下标放入到testSet内
# 从训练下标集合中删除
randIndex = int(random.uniform(0,len(trainingSet)))
testSet.append(trainingSet[randIndex])
del(trainingSet[randIndex])
# 根据trainingSet组成trainMat矩阵 为2维
trainMat = []
# 训练邮件结果
trainClasses = []
for docIndex in trainingSet:
trainMat.append(setofWords2Vec(vocabList, docList[docIndex]))
trainClasses.append(classList[docIndex])
p0V, p1V, pSpam = trainNB0(array(trainMat),array(trainClasses))
errorCount = 0
for docIndex in testSet:
wordVector = setofWords2Vec(vocabList,docList[docIndex])
if classifyNB(array(wordVector), p0V, p1V, pSpam) != classList[docIndex]:
errorCount += 1
print('the error rate is: ',float(errorCount)/len(testSet))
spamTest()
email数据集下载地址:
https://download.csdn.net/download/cx_mors/10782081