import numpy as np
from functools import reduce
"""
函数说明:创建实验样本
Parameters:无
Returns:
postingList - 实验样本切分的词条
classVec - 类别标签向量
Modify:
2019-03-21
"""
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] # 标签向量 0:非侮辱性 1:侮辱性
return postingList, classVec
"""
函数说明:将切分的实验样本整理成不重复的词条列表,即词汇表
(把出现过的词汇记录下来)
Parameters:
dataSet - 实验样本划分的词条
Returns:
vocabSet - 词汇表
Modify:
2019-03-21
"""
def createVocabList(dataSet):
vocabSet = set([]) # 创建集合,存放出现过的词汇。
for document in dataSet:
vocabSet = vocabSet | set(document) # 集合的或操作即两个集合取并集
# 集合的性质:“无序非重”
# 将无序的集合变成有序的列表,方便使用
return list(vocabSet)
"""
函数说明:根据词汇表,将词条向量化
Parameters:
vocabList - 词汇表(记录了所有词汇)
inputSet - 实验样本划分的词条
Returns:
returnVec - 向量化后的词条
Modify:
2019-03-21
"""
def setOfWords2Vec(vocabList, inputSet):
print("\n词汇表=", vocabList, "\n词条=", inputSet)
returnVec = [0] * len(vocabList) # 长度与词汇表相同,用0填充的向量
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] = 1
else:
print("警告:词汇表中没有词汇", word) # 正常情况下词汇表中应该会包含全部词汇
print("向量化后的词条:\n", returnVec)
return returnVec
# 假设词汇表: [a,b,c,d,e,f,g,h]
# 假设将进行向量化的词条: [d,e,f,b]
# 词条向量化:
# 1:创建与词汇表等成的以0填充的向量: [0,0,0,0,0,0,0,0]
# 2: 词条向量化: [0,1,0,1,1,1,0,0]
"""
函数说明:朴素贝叶斯分类器训练函数
Parameters:
trainMatrix - 词条向量构成的矩阵
trainCategory - 标签向量
Returns:
p0Vect - 非侮辱性条件概率数组
p1Vect - 侮辱性条件概率数组
pAbusive - 文档属于侮辱类的概率
Modify:
2019-03-21
"""
"""
P(侮辱性|(词汇1 词汇2 词汇3 ...词汇n)) 词条中出现了这些词汇的条件下,词条具有侮辱性的概率
= P(侮辱性)*P((词汇1 词汇2 词汇3 ...词汇n)|侮辱性)/P(词汇1 词汇2 词汇3 ...词汇n)
= P(侮辱性)*P(词汇1|侮辱性)*P(词汇2|侮辱性)*P(词汇3|侮辱性)*......P(词汇n|侮辱性)/P(词汇1 词汇2 词汇3 ...词汇n) 假设条件独立
向量化后的词条集合: 标签向量:
[[1 0 1 0 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0] [0, 1, 0, 1, 0, 1]
[0 0 0 1 0 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 0 1 1 0 0 0 0 1 0 1 0]
[1 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 1 1 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 0 0 0 0 1]
[1 0 0 1 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 1 1 0 0 1 0 1 0 1 0 0 0 0]
[0 0 0 0 0 0 0 0 1 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0]]
"""
def trainNB0(trainMatrix, trainCategory):
numTrainDocs = len(trainMatrix) # 词条总数
numWords = len(trainMatrix[0]) # 每个词条中的词汇数
pAbusive = sum(trainCategory) / float(numTrainDocs) # P(侮辱性词条)= 侮辱性词条数/词条总数
p0Num = np.zeros(numWords) # 长度为词条长度,以0填充的矩阵
p1Num = np.zeros(numWords)
p0Demon = 0.0
p1Demon = 0.0
for i in range(numTrainDocs):
if trainCategory[i] == 1:
p1Num += trainMatrix[i] # [词汇i出现在侮辱性词条中的次数]
p1Demon += sum(trainMatrix[i])
else:
p0Num += trainMatrix[i] # [词汇i出现在非侮辱性词条中的次数]
p0Demon += sum(trainMatrix[i])
p1Vect = p1Num / p1Demon # [ P(词汇1|侮辱性) P(词汇2|侮辱性) P(词汇3|侮辱性)......P(词汇n|侮辱性)] 每个词汇属于侮辱词汇的概率
p0Vect = p0Num / p0Demon # [ P(词汇1|非侮辱性) P(词汇2|非侮辱性) P(词汇3|非侮辱性)......P(词汇n|非侮辱性)] 每个词汇属于非侮辱词汇的概率
return p0Vect, p1Vect, pAbusive
"""
在使用trainNB0函数的时候发现一些问题:
如果新实例文本,包含这种概率为0的分词,那么最终的文本属于某个类别的概率也就是0了。
显然,这样是不合理的,为了降低这种影响,可以将所有词的出现数初始化为1,并将分母初始化为2。
这种做法就叫做拉普拉斯平滑(Laplace Smoothing)又被称为加1平滑,是比较常用的平滑方法,它就是为了解决0概率问题。
除此之外,另外一个遇到的问题就是下溢出:
这是由于太多很小的数相乘造成的。学过数学的人都知道,两个小数相乘,越乘越小,这样就造成了下溢出。
在程序中,在相应小数位置进行四舍五入,计算结果可能就变成0了。为了解决这个问题,对乘积结果取自然对数。
通过求对数可以避免下溢出或者浮点数舍入导致的错误。同时,采用自然对数进行处理不会有任何损失。
"""
def trainNB0_Plus(trainMatrix, trainCategory):
numTrainDocs = len(trainMatrix) # 词条总数
numWords = len(trainMatrix[0]) # 每个词条中的词汇数
pAbusive = sum(trainCategory) / float(numTrainDocs) # P(侮辱性词条)= 侮辱性词条数/词条总数
p0Num = np.ones(numWords) # 长度为词条长度,以0填充的矩阵
p1Num = np.ones(numWords)
p0Demon = 2.0
p1Demon = 2.0
for i in range(numTrainDocs):
if trainCategory[i] == 1:
p1Num += trainMatrix[i] # [词汇i出现在侮辱性词条中的次数]
p1Demon += sum(trainMatrix[i])
else:
p0Num += trainMatrix[i] # [词汇i出现在非侮辱性词条中的次数]
p0Demon += sum(trainMatrix[i])
p1Vect = np.log(p1Num / p1Demon) # log [ P(词汇1|侮辱性) P(词汇2|侮辱性) P(词汇3|侮辱性)......P(词汇n|侮辱性)] 每个词汇属于侮辱词汇的概率
p0Vect = np.log(p0Num / p0Demon) # log [ P(词汇1|非侮辱性) P(词汇2|非侮辱性) P(词汇3|非侮辱性)......P(词汇n|非侮辱性)] 每个词汇属于非侮辱词汇的概率
return p0Vect, p1Vect, pAbusive
"""
函数说明:使用朴素贝叶斯分类器进行分类
Parameters:
vec2Classify - 待分类的词条数组
p0Vec - 每个词汇属于非侮辱词汇的概率 [ P(词汇1|非侮辱性) P(词汇2|非侮辱性) P(词汇3|非侮辱性)......P(词汇n|非侮辱性)]
p1Vec - 每个词汇属于侮辱词汇的概率 [ P(词汇1|侮辱性) P(词汇2|侮辱性) P(词汇3|侮辱性)......P(词汇n|侮辱性)]
pClass1 - 文档属于侮辱类的概率 P(侮辱类)
Returns:
0 - 属于非侮辱类
1 - 属于侮辱类
Modify:
2019-03-22
"""
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
p1 = reduce(lambda x, y: x * y, vec2Classify * p1Vec) * pClass1
p0 = reduce(lambda x, y: x * y, vec2Classify * p0Vec) * (1.0 - pClass1)
"""
reduce(function,可迭代序列)
函数将一个数据集合(链表,元组等)中的所有数据进行下列操作:
用传给 reduce 中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,
得到的结果再与第三个数据用 function 函数运算,最后得到一个结果。
lambda:python中生成匿名函数的方法
例子:reduce(lambda x.y:x+y,[1,2,3,4])
相当于 1+2 -> (1+2)+3 -> ((1+2)+3)+4
P(侮辱|词条) = P(侮辱)*P(词条|侮辱)/P(词条)
P(正常|词条) = P(正常)*P(词条|正常)/P(词条)
因为只需要比较词条属于侮辱类和非侮辱类的概率,所以:
P(侮辱|词条) = P(侮辱)*P(词条|侮辱)
P(正常|词条) = P(正常)*P(词条|正常)
因为朴素贝叶斯算法假设各条件相互独立:
P(侮辱|词条) = P(侮辱)*P(词条|侮辱) = P(侮辱)*P(词汇1|侮辱)*P(词汇2|侮辱)*......P(词汇n|侮辱)
P(正常|词条) = P(正常)*P(词条|正常) = P(正常)*P(词汇1|正常)*P(词汇2|正常)*......P(词汇n|正常)
vec2Classify * p1Vec = [词汇i是否存在]*[P(词汇i|侮辱)]
例:[1,0,1,1,0]*[0.01,0.02,0.00,0.03,0.00]=[0.01,0.00,0.00,0.03,0.00]
reduce(lambda x, y: x * y, vec2Classify * p1Vec) = P(词汇1|侮辱)*P(词汇2|侮辱)*......P(词汇n|侮辱)
例:0.01*0.00*0.00*0.03*0.00 由此看出本算法存在缺陷,需要改进
p1 = reduce(lambda x, y: x * y, vec2Classify * p1Vec) * pClass1
= P(词条|侮辱) = P(侮辱)*P(词汇1|侮辱)*P(词汇2|侮辱)*......P(词汇n|侮辱)*P(侮辱)
= P(侮辱|词条)
"""
print("侮辱类概率:", p1, " 非侮辱类概率:", p0)
if p1 > p0:
return 1
else:
return 0
"""
由于想要通过取对数的方式解决下溢出
"""
def classifyNB_plus(vec2Classify, p0Vec, p1Vec, pClass1):
p1 = sum(vec2Classify * p1Vec) + np.log(pClass1) # log(ABCDE)=log(A)+log(B)+log(C)+log(D)+log(E)
p0 = sum(vec2Classify * p0Vec) + np.log(1.0 - pClass1)
print("侮辱类概率:", p1, " 非侮辱类概率:", p0)
if p1 > p0:
return 1
else:
return 0
"""
函数说明:测试朴素贝叶斯分类器
Parameters:
无
Returns:
无
Modify:
2019-03-22
"""
def testingNB():
list0Posts, listClasses = loadDataSet() # 词条集合,词条类别标签
myVocabList = createVocabList(list0Posts) # 词汇表
print("词汇表:\n", myVocabList)
print("标签向量:\n", listClasses)
trainMat = []
for postinDoc in list0Posts: # 逐个词条进行向量化
trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
print("向量化后的词条集合:\n", np.array(trainMat)) # 为了方便展示,使用了numpy数组
p0V, p1V, pAb = trainNB0_Plus(trainMat, listClasses)
print("[P(词汇i|非侮辱性)]:\n", p0V)
print("[P(词汇i|侮辱性)]:\n", p1V)
print("P(侮辱性):\n", pAb)
testEntry = ['love', 'my', 'dalmation'] # 测试样本1
thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry)) # 测试样本向量化
if classifyNB_plus(thisDoc, p0V, p1V, pAb):
print(testEntry, "具有侮辱性")
else:
print(testEntry, "不具侮辱性")
if __name__ == '__main__':
testingNB()
机器学习实战--朴素贝叶斯分类器--学习笔记
猜你喜欢
转载自blog.csdn.net/qq_39514033/article/details/88741542
今日推荐
周排行