自然语言处理三巨头(NB、HMM、CRF)

NB框架


HMM框架


CRF框架

解释一下,为什么称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)\Pi 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类别的训练集样本数。(一般来说直接使用默认值就好)


来自:https://www.cnblogs.com/eniac1946/p/7406438.html

介绍完SKlearn中的MultinomialNB之后,我们再来看看这个比赛的数据集是什么样的。


一共有3个csv文件,分别为训练集、验证集与测试集


训练集与验证集的数据长这样,其中第一列为文本,第二列为类别


测试集长这样,第一列为id,第二列为文本

我们需要用训练集训练出一个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条数据,得到预测结果


用2k条数据训练的NB模型预测5K条数据的结果

完事,直接提交,来看看结果


评分就是预测准确率百分比

然后我又用服务器在全部训练集上跑了一下,结果如下:


比仅使用2k训练集训练出的模型在测试集上高了8个点

4.2去停用词

这里就不上代码了,直接看结果就好。


使用2k训练集并去停用词训练的模型结果

竟然比没去停用词还要低。。


使用全部训练集并去停用词训练的模型结果

还是比没去停用词的时候低。。

4.3理性分析去停用词之后模型反而更差的原因

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容