import numpy as np
import logging as log
#生成实验样本
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=vocabSet|set(document) #取两个集合的并集
return list(vocabSet)
#词集模型 对输入的词汇表构建词向量
def setOfWords2Vec(vocabList,inputSet):
returnVec=np.zeros(len(vocabList)) #生成零向量的array
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)]=1 #有单词,则该位置填充0
else: print('the word:%s is not in my Vocabulary!'% word)
return returnVec #返回全为0和1的向量
#词袋模型
def bagOfWords2VecMN(vocabList,inputSet):
returnVec=[0]*len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)]+=1
return returnVec #返回非负整数的词向量
def trainNB0(trainMatrix,trainCategory):
numTrainDocs=len(trainMatrix) #文档数目
numWord=len(trainMatrix[0]) #词汇表词数目
print("numDocs=",numTrainDocs,"numword=",numWord)
pAbusive=sum(trainCategory)/len(trainCategory) #p1,出现侮辱性评论的概率
p0Num=np.zeros(numWord);p1Num=np.zeros(numWord)
p0Demon=0;p1Demon=0
for i in range(numTrainDocs):
if trainCategory[i]==0:
p0Num+=trainMatrix[i] #向量相加
p0Demon+=sum(trainMatrix[i]) #向量中1累加求和
else:
p1Num+=trainMatrix[i]
p1Demon+=sum(trainMatrix[i])
print("p0Num=", p0Num)
print("p1Demon=", p1Demon)
p0Vec=p0Num/p0Demon
p1Vec=p1Num/p1Demon
return p0Vec,p1Vec,pAbusive
def trainNB1(trainMatrix,trainCategory):
numTrainDocs=len(trainMatrix)
numWord=len(trainMatrix[0])
pAbusive=sum(trainCategory)/len(trainCategory)
p0Num=np.ones(numWord)
p1Num=np.ones(numWord)# 初始化为1
p0Demon=2;p1Demon=2 #初始化为
for i in range(numTrainDocs):
if trainCategory[i]==0:
p0Num+=trainMatrix[i]
p0Demon+=sum(trainMatrix[i])
else:
p1Num+=trainMatrix[i]
p1Demon+=sum(trainMatrix[i])
print("p0Num=",p0Num)
p0Vec=log(p0Num/p0Demon) #对结果求对数
p1Vec=log(p1Num/p1Demon) #对结果求自然对数
return p0Vec,p1Vec,pAbusive
if __name__ == '__main__':
listPosts,listClasses=loadDataSet()
myVocabList=createVocabList(listPosts)
print(myVocabList)
print(setOfWords2Vec(myVocabList,listPosts[0]))
trainMat=[]
for postinDoc in listPosts:
trainMat.append(setOfWords2Vec(myVocabList,postinDoc))
print("trainMat=",trainMat)
p0v,p1v,pAb = trainNB0(trainMat,listClasses)
print("p0v=", p0v)
print("p1v=", p1v)
print("pAb=", pAb)
print("p0v[19]=",p0v[19])
print("p1v[19]=", p1v[19])
总结:
1.loadDataSet()
获取数据 比如是一些对话内容,我们判断对话内容是否是侮辱性言论
列举出一些侮辱性言论,一些非侮辱性言论,两者数量相当,一个数组标记那一条数据是侮辱性,那些是非侮辱性,这样就有两个数组,一个数组保存这些言论,一个数组存储每一条言论对应的分类,1为侮辱性言论,0为非侮辱性言论。
2.获取言论中所有词组成的一个数组,这里用到了set()函数,创建一个无序不重复元素集,通过|可以得到所有词组成的一个数组vocabList,对应createVocabList()方法.
vocabList = ['cute', 'take', 'stop', 'maybe', 'I', 'licks', 'mr', 'food', 'help', 'not', 'garbage', 'stupid', 'worthless', 'love', 'flea', 'quit', 'buying', 'him', 'posting', 'my', 'to', 'how', 'is', 'please', 'has', 'ate', 'dalmation', 'problems', 'steak', 'dog', 'so', 'park']
3.获取每条言论对应的词向量,向量的维数为整个数据集所有的词的个数,这个词如果在指定的这条言论中出现了,那么对应的词在向量中这个值设为1,由setOfWords2Vec(vocabList,inputSet)方法实现。vocabList为整个数据集中出现的词构成的列表,inputSet为指定的一条言论。下面的就是输出的指定的言论对应的词向量
[0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 1. 0. 0. 0. 1.1. 0. 0. 1. 0. 1. 0. 0.]
这种构建词向量的方法,只记录了每个词是否出现,而没有记录词出现的次数,这样的模型叫做词集模型,如果在词向量中记录词出现的次数,没出现一次,则多记录一次,这样的词向量构建方法,被称为词袋模型
4.将数据集中的每条言论的词向量添加到一个数组,得到trainMat
5.我们已知了每个言论是否为侮辱性言论,可以得到数据中每个词在它所在的分类中出现的概率。所有同一分类的词向量相加,如果用的是词集模型获取的词向量,那么得到的是这个分类中每个词在言论中出现的次数的向量(p0Num,p1Num),同一条言论中的不累加,如果是词袋模型,得到的是每个词在言论中总共出现的次数,同一条言论中是累加的. p0Vec=p0Num/p0Demon为以每个词在这个分类中出现的概率组成的矩阵。比如“love”在vocabList 中的索引是19,p0Vec[19]= 0.041666666666666664,
p1Vec[19]= 0.0即就是love在侮辱性言论中出现的概率为0。
pAbusive=sum(trainCategory)/len(trainCategory),表示文档集中分类为1的文档数目,累加求和将词向量中所有1相加,len求长度函数则对所有0和1进行计数,最后得到分类为1的概率
算法漏洞:
- 乘积为0
我们看到,当某分类下某词项出现频次为0时,其概率也是0,因此在计算p(w0|ci)p(w1|ci)p(w2|ci)......p(wN|ci)p(w0|ci)p(w1|ci)p(w2|ci)......p(wN|ci)会因为其中某个的概率为0而全部是0。
为了避免这样的情况发生,我们将所有词项出现的频次都初始化为1,某类所有词项数量初始化为2。 - 因子太小导致结果溢出问题
由于p(w0|ci)p(w1|ci)p(w2|ci)......p(wN|ci)p(w0|ci)p(w1|ci)p(w2|ci)......p(wN|ci)中每个因子都很小,所有因子相乘,特别是因子数量多的时候,会导致结果溢出,从而得到错误的数据
避免溢出问题的发生,可以使用求自然对数的方法,自然对数和原本的数值同增同减,不会有任何损失,因此不会影响求得的概率结果。
def trainNB1(trainMatrix,trainCategory):
numTrainDocs=len(trainMatrix)
numWord=len(trainMatrix[0])
pAbusive=sum(trainCategory)/len(trainCategory)
p0Num=np.ones(numWord)
p1Num=np.ones(numWord)# 初始化为1
p0Demon=2;p1Demon=2 #初始化为
for i in range(numTrainDocs):
if trainCategory[i]==0:
p0Num+=trainMatrix[i]
p0Demon+=sum(trainMatrix[i])
else:
p1Num+=trainMatrix[i]
p1Demon+=sum(trainMatrix[i])
print("p0Num=",p0Num)
p0Vec=log(p0Num/p0Demon) #对结果求对数
p1Vec=log(p1Num/p1Demon) #对结果求自然对数
return p0Vec,p1Vec,pAbusive
用分类函数进行分类,取概率较大者为该言论的分类,分类函数:
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
p1=sum(vec2Classify*p1Vec)+np.log(pClass1)
p0=sum(vec2Classify*p0Vec)+np.log(1-pClass1)
if p1>p0:
return 1
else:
return 0
testEntry = ['love', 'my', 'dalmation']
thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
print(testEntry, 'classified as:', classifyNB(thisDoc, p0v, p1v, pAb))
testEntry = ['stupid', 'garbage']
thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
print(testEntry, 'classified as:', classifyNB(thisDoc, p0v, p1v, pAb))
输出:
['love', 'my', 'dalmation'] classified as: 0
['stupid', 'garbage'] classified as: 1
参考网址:https://blog.csdn.net/moxigandashu/article/details/71480251?locationNum=16&fps=1