朴素贝叶斯
1.得到数据
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]
return postingList,classVec
postingList是一个列表,里面存储6个列表,每个列表里面的单词组成一句话,classVec里面是标签,0代表非侮辱性文档,1代表侮辱性文档。例如:my dog has flea problems help please 就不是一句侮辱人的话,而quit buying worthless dog food stupid 就是一句侮辱性的话。
2.得到文档向量
对于文档分类任务,我们可以把每个词的出现或者不出现作为一个特征,简单来说,我们需要把一句话用一串0或者1的序列表示出来。
那么第一步,我们就先需要统计上述句子里面到底出现了多少单词。
def createVocabList(dataset):
vocabSet=set([])
for document in dataset:
vocabSet=vocabSet|set(document)
return list(vocabSet)
上述任务就是在统计postingList里面到底有多少不同的单词,| 是一个求并集的运算符,该运算符两边要求都是set对象。第二步就是把每个句子向量化,我们现在已经得到vocabSet,这是一个含有所有单词的列表。每个单词在vocabSet列表里面不同的位置上,比如可能my在0号位置,dog在1号位置,这是呢,对于这my dog has flea problems help please 我们就需要构造一个向量,让这句话对应的向量的0号位置,1号位置都为1.
def setOfWords2Vec(vocabList,inputSet):
returnVec=[0 for i in range(len(vocabList))]
for word in inputSet:
if word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)]=1
else:
print(word+"is not in vocabList")
return returnVec
上面代码里面我们就构造一个returnVec向量,他的大小和vocabSet一样大,初始全为0.vocabList.index(word)这句话就是找出word在vocabList下标位置。
3.进行统计
我们现在需要统计每个单词在两类句子里面出现的概率和两类句子出现的概率。
from numpy import *
def trainNB0(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
上面的代码中我们先去计算p0Vect和p1Vect这两个向量,这是一个1 x len(vocabSet)大小的向量,vocabSet里面单词和p0Vect和p1Vect里面的概率一一对应。p1Denom代表1标签句子里面单词的个数,p0Denom代表0标签句子里面单词的个数。为什么在最后计算log是因为概率通常是小于1的,为了防止相乘过小,我们使用ln(a*b)=ln(a)+ln(b)来代替。p0Vect和p1Vect初始化一定不能为0,这样可能导致概率为0,会出错。pAbusive代表文档里面1标签句子出现的概率,因为这是一个二分类,所以1-pAbusive就代表0标签句子出现的概率。
4.进行分类
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
假设我们输入测试的句子是 stupid garbage,我们通过贝叶斯准则可以得到以下公式:
p(侮辱性句子|stupid garbage)=p(stupid garbage|侮辱性句子)*P(侮辱性句子)/p(stupid garbage)
p(非侮辱性句子|stupid garbage)=p(stupid garbage|非侮辱性句子)*p(非侮辱性句子)/p(stupid garbage)
因为我们只需要比较p(侮辱性句子|stupid garbage)和p(非侮辱性句子|stupid garbage)的大小,所以就不用需要计算p(stupid garbage)
根据贝叶斯公式的假设p(stupid garbage|侮辱性句子)=p(stupid|侮辱性句子)*p(garbage|侮辱性句子)
再根据ln(a*b)=ln(a)+ln(b)
所以变换后我们需要比较
p(侮辱性句子|stupid garbage)=ln(p(stupid garbage|侮辱性句子))+ln(P(侮辱性句子))
=ln(p(stupid|侮辱性句子))+ln(p(garbage|侮辱性句子))+ln(p(侮辱性句子))
p(非侮辱性句子|stupid garbage)=ln(p(stupid garbage|非侮辱性句子))+ln(P(非侮辱性句子))
=ln(p(stupid|非侮辱性句子))+ln(p(garbage|非侮辱性句子))+ln(p(非侮辱性句子))
5.扩展
最后讲那个情感分离其实和这个是一样的,但是在数据处理方面需要下点功夫,我们需要使用一个分词工具包pkuseg(其实什么都可以,比如jieba分词也可以进行分个词),利用pandas读取csv文件。
这个不是重点,我就不啰嗦了,怎么处理我就贴出来就行了。安装pkuseg可以使用这个命令
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple pkuseg
代码如下:
def get_Data():
train_data=[]
train_class=[]
dev_data=[]
dev_class=[]
seg=pkuseg.pkuseg()
train_csv=pd.read_csv("../data/train_data.csv",usecols=["sentence","label"])
dev_csv=pd.read_csv("../data/dev_data.csv",usecols=["sentence","label"])
train_num=1000
dev_num=100
for i in range(train_num):
sentence=train_csv["sentence"][i+1]
label=train_csv["label"][i+1]
sentence=[word for word in seg.cut(sentence) if len(word)>=2]
if label=="negative":
label=0
else:
label=1
train_data.append(sentence)
train_class.append(label)
for i in range(dev_num):
sentence=dev_csv["sentence"][i+1]
label=dev_csv["label"][i+1]
sentence = [word for word in seg.cut(sentence) if len(word) >= 2]
if label == "negative":
label = 0
else:
label = 1
dev_data.append(sentence)
dev_class.append(label)
return train_data,train_class,dev_data,dev_class