解释一下,为什么称NB、HMM、CRF为NLP三巨头:在1990~2014年之间,NLP主要的算法就是基于统计的NB、HMM、CRF。
一、Naive Bayes(朴素贝叶斯)
1.概述
Naive Bayes法是基于贝叶斯定理与特征条件独立假设的分类法 。首先基于特征条件独立假设(这也是它之所以naive的原因)学习输入输出的联合概率分布,然后基于此模型,对给定的输入x,利用贝叶斯定理求出后验概率最大的输出y。
2.训练过程
给定数据集 T = {(x1,y1),(x2,y2), ...,(xn,yn)}
①计算先验概率分布
P{Y=ck} k = 1,2,3...,k
②估计条件概率分布
P(X=x|Y=ck),于是学习到联合概率分布P(X,Y)
③分类器表示
Y = argmax P(Y=ck)P(Xi = xi | Y=ck)
3.估计方法
(1)极大似然估计
(2)贝叶斯估计:用极大似然估计可能会出现所要估计的概率值为0的情况,这时会影响到后验概率的计算结果,使分类产生偏差。
4.实战
本次实战的是AI研习社上的一个小比赛——中文对话情感分析,现在已经结束,但是大家还可以提交结果进行练习:https://god.yanxishe.com/5
我们使用的是sklearn中的NB函数,在scikit-learn中,一共有3个朴素贝叶斯的分类算法类。分别是GaussianNB,MultinomialNB和BernoulliNB。其中GaussianNB就是先验为高斯分布的朴素贝叶斯,MultinomialNB就是先验为多项式分布的朴素贝叶斯,而BernoulliNB就是先验为伯努利分布的朴素贝叶斯。这三个类适用的分类场景各不相同,一般来说,如果样本特征的分布大部分是连续值,使用GaussianNB会比较好。如果样本特征的分布大部分是多元离散值,使用MultinomialNB比较合适。而如果样本特征是二元离散值或者很稀疏的多元离散值,应该使用BernoulliNB。我们的任务是给不同的句子分类,故为离散值,这里使用的是MultinomialNB。
class sklearn.naive_bayes.MultinomialNB(alpha=1.0, fit_prior=True,class_prior=None)
我们来看一下MultinomialNB的参数,①alpha代表平滑项,默认为1,即拉普拉斯平滑,这里对应的是上述3.估计方法中的(2),为了考虑极大似然法估计可能会出现概率值为0的情况而引入平滑项,如无特殊需求,则直接使用拉普拉斯平滑。如果发现拟合的不好,需要调优时,可以选择稍大于1或者稍小于1的数。②布尔参数fit_prior表示是否要考虑先验概率,如果是false,则所有的样本类别输出都有相同的类别先验概率。否则可以自己用③第三个参数class_prior输入先验概率,或者不输入第三个参数class_prior让MultinomialNB自己从训练集样本来计算先验概率,此时的先验概率为P{Y=ck} = mk/m。其中m为训练集样本总数量,mk为输出为第k类别的训练集样本数。(一般来说直接使用默认值就好)
介绍完SKlearn中的MultinomialNB之后,我们再来看看这个比赛的数据集是什么样的。
我们需要用训练集训练出一个NB模型,然后用该模型对测试集进行测试,再讲测试结果提交即可查看我们的预测成绩。
由于该数据集中的文本已经去除了非汉语的字符已经分好词了,所以我们可以直接上手,但不难得知,貌似没有去停用词,所以我打算去停用词与不去停用词分别训练一次模型,并将结果进行比较。
依赖库:
from collections import Counter
from numpy import array
from sklearn.naive_bayes import MultinomialNB
import pandas as pd
import numpy as np
4.1不去除停用词
data = pd.read_csv('training_set.csv',encoding='gbk')
data = data.values.tolist()
articles = list()
labels = list()
for i in data:
articles.append(i[0].split(' '))
if i[1] == 'positive':
labels.append(1)
elif i[1] == 'negative':
labels.append(0)
else:
print("存在异常错误")
labels = array(labels)
allwords = set()
for i in articles:
for j in i:
allwords.add(j)
allwords = list(allwords)
vector = list()
for words in articles:
temp = list(map(lambda x:words.count(x),allwords))
print(len(temp))
vector.append(temp)
model = MultinomialNB()
model.fit(vector,labels)
至此,模型训练完毕,接着我们对测试集的数据进行预测,并将预测结果保存成csv文件
def predict(string):
words = string.split(' ')
currentVector = array(tuple(map(lambda x:words.count(x),allwords)))
result = model.predict(currentVector.reshape(1,-1))
if result == 1:
return "positive"
elif result == 0:
return "negative"
else:
print('出现异常 请检查')
test = pd.read_csv('test_set.csv',encoding='gbk')
test = test.values.tolist()
results = list()
for i in test:
a = list()
id_num = i[0]
result = predict(i[1])
a.append(id_num)
a.append(result)
results.append(a)
test=pd.DataFrame(data=results)
test.to_csv('result.csv',encoding='gbk',index=None,header=None)
运行结果如下图所示
于是我自己,截取了训练集的前2000条进行训练,然后再预测测试集的5000条数据,得到预测结果
完事,直接提交,来看看结果
然后我又用服务器在全部训练集上跑了一下,结果如下:
4.2去停用词
这里就不上代码了,直接看结果就好。
竟然比没去停用词还要低。。
还是比没去停用词的时候低。。