[准确率:98%] 改进朴素贝叶斯自动分类食品安全新闻

发表于 Python, 机器学习, 神经网络及深度学习, 程序语言, 算法 2018-11-29 阅读数: 32

这是本系列第二篇文章,位于源代码的 2. NB_Weights 中:

https://github.com/Ckend/NLP_DeepLearning_CN_Tutorial

前一篇文章中,我们学习了如何使用朴素贝叶斯自动分类食品安全新闻,准确率为97%,这一篇文章将教大家如何改进这个模型。阅读本篇文章之前,建议先阅读前一篇文章:[准确率:97%] 朴素贝叶斯自动分类食品安全新闻,否则有些概念可能无法理解。

在那篇文章中,在训练的时候,朴素贝叶斯模型中所有词语都是相同的权重,而事实上真的如此吗?我们怎么样才可以知道哪些词语更加重要呢?这时候,数理统计就派上用场了。

我们先对所有的食品安全新闻和非食品安全新闻使用结巴(jieba)分词, 然后统计各个词性在这分别在这两个类别中的数量,比如说名词的结果如下表(使用SPSS得到,其他词性就不一一展示了),显然食品安全新闻中名词的数量多于非食品安全新闻,这也是在人意料之中的结果,但是这并不代表着对于食品安全新闻,名词的重要性就大于其他的词性:

改进朴素贝叶斯-1

那么如何确定各个词性对分类的重要性呢?单纯根据频率和频数确定是比较复杂的,我们可以尝试使用我们的模型,比如说,先得到一个基准的准确值,然后尝试去除掉名词得到一个准确值,观察这两个准确值的差距,如果非常大,说明名词具有比较重要的地位。我们可以试一下:

在所有词性权重都为1的情况下(基准)进行训练,准确率为:

改进朴素贝叶斯-2

如果说,名词权重为0呢?

改进朴素贝叶斯-3

不过,没有对比是没有意义的,我们尝试令形容词权重为0,看看怎么样:

改进朴素贝叶斯-4

可以看到几乎没有影响,也就是说,对于我们的分类器而言,名词的重要性远远大于形容词。这样,我们可以尝试增加名词的权重,看看效果怎么样:

改进朴素贝叶斯-5

准确率 0.98,效果显著,不过我们很难确定最佳的权重,只能通过(玄学)调参来找到最合适的权重,你也可以尝试用神经网络来确定权重,虽然容易过拟合,但也是一种方法。不过既然用上了神经网络,就有更优秀的模型可以使用了,我们下次再介绍吧。

接下来讲一下这个权重的实现原理(要是不耐烦,可以直接看文章首行的源代码):基于前一篇文章,我们修改jieba_cut_and_save_file这个函数,这个函数在训练的时候用到了,它修改的就是训练时每个新闻被向量化而成的值,如下所示:

改进朴素贝叶斯-6

将该函数改成这样:


def jieba_cut_and_save_file(inputList, n_weight, a_weight, output_cleaned_file=False):

    """

   1. 读取中文文件并分词句子

   2. 可以将分词后的结果保存到文件

   """

    output_file = os.path.join('./data/', 'cleaned_' + 'trainMatrix.txt')

    lines = []

    tags = []

    for line in inputList:

        result = pseg.cut(clean_str(line))

        a = []

        b = []

        for word, flag in result:

            # 对分词后的新闻

            if word != ' ':

                # 若非空

                a.append(word)

                if flag.find('n')==0:

                    # 若是名词

                    b.append(n_weight)

                elif flag.find('a')==0:

                    # 若形容词

                    b.append(a_weight)

                # elif flag.find('v')==0:

                #     # 若名词

                #     b.append(v_weight)

                else:

                b.append(1)

        lines.append(a)

        tags.append(b)

    if output_cleaned_file:

    with open(output_file, 'w') as f:

    for line in lines:

    f.write(" ".join(line) + '\n')

    vocabulary = createVocabList(lines)

    # 根据词典生成词向量化器,并进行词向量化

    setOfWords2Vec = setOfWords2VecFactory(vocabulary)

    vectorized = []

    for i,news in enumerate(lines):

    vector = setOfWords2Vec(news, tags[i])

    vectorized.append(vector)

    return vectorized, vocabulary

最后,在主函数调用的时候传入你想需要的参数即可,你可以按照代码,修改任意词性权重,不过要注意结巴的词性表(每种词性的字母),你可以搜索“ictclas 词性表”得到。

import bayes

from data_helpers import *

from sklearn.externals import joblib

posFile = "./data/train_food.txt"

negFile = "./data/train_notfood.txt"

print("正在获取训练矩阵及其分类向量")

trainList,classVec = loadTrainDataset(posFile,negFile)

print("正在将训练矩阵分词,并生成词表")

n_weight = 3

# 名词权重

a_weight = 1

# 形容词权重

vectorized, vocabulary = jieba_cut_and_save_file(trainList, n_weight, a_weight, True)

bayes_ = bayes.oldNB(vocabulary)

# 初始化模型

print("正在训练模型")

bayes_.train(vectorized, classVec)

# 训练

print("保存模型")

joblib.dump(bayes_, "./arguments/train_model.m")

最后总结一下,我们通过修改训练集新闻中不同词性的权重,加大名词权重,从而提高朴素贝叶斯模型的准确率到98%,不过,这个仅仅是在食品安全新闻这个例子中是这样,你如果想要应用到自己的程序上,应该先找到你的关键词性。下一篇文章我们将尝试一些新的模型元素。如果你喜欢的话,请继续关注幻象客。

Add comment