首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

NLP之文本分类:“Tf-Idf、Word2Vec和BERT”三种模型比较

概要

在本文中,我将使用NLP和Python来解释3种不同的文本多分类策略:老式的词袋法(tf-ldf),著名的词嵌入法(Word2Vec)和最先进的语言模型(BERT)。

NLP(自然语言处理)是人工智能的一个领域,它研究计算机和人类语言之间的交互作用,特别是如何通过计算机编程来处理和分析大量的自然语言数据。NLP常用于文本数据的分类。文本分类是指根据文本数据内容对其进行分类的问题。

我们有多种技术从原始文本数据中提取信息,并用它来训练分类模型。本教程比较了传统的词袋法(与简单的机器学习算法一起使用)、流行的词嵌入模型(与深度学习神经网络一起使用)和最先进的语言模型(和基于attention的transformers模型中的迁移学习一起使用),语言模型彻底改变了NLP的格局。

我将介绍一些有用的Python代码,这些代码可以轻松地应用在其他类似的案例中(仅需复制、粘贴、运行),并对代码逐行添加注释,以便你能复现这个例子(下面是全部代码的链接)。

我将使用“新闻类别数据集”(News category dataset),这个数据集提供了从HuffPost获取的2012-2018年间所有的新闻标题,我们的任务是把这些新闻标题正确分类,这是一个多类别分类问题(数据集链接如下)。

特别地,我要讲的是:

设置:导入包,读取数据,预处理,分区。

词袋法:用scikit-learn进行特征工程、特征选择以及机器学习,测试和评估,用lime解释。

词嵌入法:用gensim拟合Word2Vec,用tensorflow/keras进行特征工程和深度学习,测试和评估,用Attention机制解释。

语言模型:用transformers进行特征工程,用transformers和tensorflow/keras进行预训练BERT的迁移学习,测试和评估。

设置

首先,我们需要导入下面的库:

该数据集包含在一个jason文件中,所以我们首先将其读取到一个带有json的字典列表中,然后将其转换为pandas的DataFrame。

原始数据集包含30多个类别,但出于本教程中的目的,我将使用其中的3个类别:娱乐(Entertainment)、政治(Politics)和科技(Tech)。

从图中可以看出,数据集是不均衡的:和其他类别相比,科技新闻的占比很小,这会使模型很难识别科技新闻。

在解释和构建模型之前,我将给出一个预处理示例,包括清理文本、删除停用词以及应用词形还原。我们要写一个函数,并将其用于整个数据集上。

该函数从语料库中删除了一组单词(如果有的话)。我们可以用nltk创建一个英语词汇的通用停用词列表(我们可以通过添加和删除单词来编辑此列表)。

现在,我将在整个数据集中应用编写的函数,并将结果存储在名为“text_clean”的新列中,以便你选择使用原始的语料库,或经过预处理的文本。

如果你对更深入的文本分析和预处理感兴趣,你可以查看这篇文章。我将数据集划分为训练集(70%)和测试集(30%),以评估模型的性能。

让我们开始吧!

词袋法

词袋法的模型很简单:从文档语料库构建一个词汇表,并计算单词在每个文档中出现的次数。换句话说,词汇表中的每个单词都成为一个特征,文档由具有相同词汇量长度的矢量(一个“词袋”)表示。例如,我们有3个句子,并用这种方法表示它们:

特征矩阵的形状:文档数x词汇表长度

可以想象,这种方法将会导致很严重的维度问题:文件越多,词汇表越大,因此特征矩阵将是一个巨大的稀疏矩阵。所以,为了减少维度问题,词袋法模型通常需要先进行重要的预处理(词清除、删除停用词、词干提取/词形还原)。

词频不一定是文本的最佳表示方法。实际上我们会发现,有些常用词在语料库中出现频率很高,但是它们对目标变量的预测能力却很小。为了解决此问题,有一种词袋法的高级变体,它使用词频-逆向文件频率(Tf-Idf)代替简单的计数。基本上,一个单词的值和它的计数成正比地增加,但是和它在语料库中出现的频率成反比。

先从特征工程开始,我们通过这个流程从数据中提取信息来建立特征。使用Tf-Idf向量器(vectorizer),限制为1万个单词(所以词长度将是1万),捕捉一元文法(即 "new "和 "york")和 二元文法(即 "new york")。以下是经典的计数向量器的代码:

现在将在训练集的预处理语料上使用向量器来提取词表并创建特征矩阵。

特征矩阵X_train的尺寸为34265(训练集中的文档数)×10000(词长度),这个矩阵很稀疏:

从特征矩阵中随机抽样(黑色为非零值)

为了知道某个单词的位置,可以这样在词表中查询:

如果词表中存在这个词,这行脚本会输出一个数字N,表示矩阵的第N个特征就是这个词。

为了降低矩阵的维度所以需要去掉一些列,我们可以进行一些特征选择(Feature Selection),这个流程就是选择相关变量的子集。操作如下:

将每个类别视为一个二进制位(例如,"科技"类别中的科技新闻将分类为1,否则为0);

进行卡方检验,以便确定某个特征和其(二进制)结果是否独立;

只保留卡方检验中有特定p值的特征。

这将特征的数量从10000个减少到3152个,保留了最有统计意义的特征。选一些打印出来是这样的:

我们将这组新的词表作为输入,在语料上重新拟合向量器。这将输出一个更小的特征矩阵和更短的词表。

新的特征矩阵X_train的尺寸是34265(训练中的文档数量)×3152(给定的词表长度)。你看矩阵是不是没那么稀疏了:

从新的特征矩阵中随机抽样(非零值为黑色)

现在我们该训练一个机器学习模型试试了。我推荐使用朴素贝叶斯算法:它是一种利用贝叶斯定理的概率分类器,贝叶斯定理根据可能相关条件的先验知识进行概率预测。这种算法最适合这种大型数据集了,因为它会独立考察每个特征,计算每个类别的概率,然后预测概率最高的类别。

我们在特征矩阵上训练这个分类器,然后在经过特征提取后的测试集上测试它。因此我们需要一个scikit-learn流水线:这个流水线包含一系列变换和最后接一个estimator。将Tf-Idf向量器和朴素贝叶斯分类器放入流水线,就能轻松完成对测试数据的变换和预测。

至此我们可以使用以下指标评估词袋模型了:

准确率: 模型预测正确的比例。

混淆矩阵: 是一张记录每类别预测正确和预测错误数量的汇总表。

ROC: 不同阈值下,真正例率与假正例率的对比图。曲线下的面积(AUC)表示分类器中随机选择的正观察值排序比负观察值更靠前的概率。

精确率:  "所有被正确检索的样本数(TP)"占所有"实际被检索到的(TP+FP)"的比例。

召回率:  所有"被正确检索的样本数(TP)"占所有"应该检索到的结果(TP+FN)"的比例。

词袋模型能够在测试集上正确分类85%的样本(准确率为0.85),但在辨别科技新闻方面却很吃力(只有252条预测正确)。

让我们探究一下为什么模型会将新闻分类为其他类别,顺便看看预测结果是不是能解释些什么。lime包可以帮助我们建立一个解释器。为让这更好理解,我们从测试集中随机采样一次, 看看能发现些什么:

这就一目了然了:虽然"舞台(stage)"这个词在娱乐新闻中更常见, "克林顿(Clinton) "和 "GOP "这两个词依然为模型提供了引导(政治新闻)。

词嵌入

词嵌入(Word Embedding)是将中词表中的词映射为实数向量的特征学习技术的统称。这些向量是根据每个词出现在另一个词之前或之后的概率分布计算出来的。换一种说法,上下文相同的单词通常会一起出现在语料库中,所以它们在向量空间中也会很接近。例如,我们以前面例子中的3个句子为例:

二维向量空间中的词嵌入

在本教程中,我门将使用这类模型的开山怪: Google的Word2Vec(2013)。其他流行的词嵌入模型还有斯坦福大学的GloVe(2014)和Facebook的FastText(2016)。

Word2Vec生成一个包含语料库中的每个独特单词的向量空间,通常有几百维, 这样在语料库中拥有共同上下文的单词在向量空间中的位置就会相互靠近。有两种不同的方法可以生成词嵌入:从某一个词来预测其上下文(Skip-gram)或根据上下文预测某一个词(Continuous Bag-of-Words)。

在Python中,可以像这样从genism-data中加载一个预训练好的词嵌入模型:

我将不使用预先训练好的模型,而是用gensim在训练数据上自己训练一个Word2Vec。在训练模型之前,需要将语料转换为n元文法列表。具体来说,就是尝试捕获一元文法("york")、二元文法("new york")和三元文法("new york city")。

在训练Word2Vec时,需要设置一些参数:

词向量维度设置为300;

窗口大小,即句子中当前词和预测词之间的最大距离,这里使用语料库中文本的平均长度;

训练算法使用  skip-grams   (sg=1),因为一般来说它的效果更好。

现在我们有了词嵌入模型,所以现在可以从语料库中任意选择一个词,将其转化为一个300维的向量。

甚至可以通过某些维度缩减算法(比如TSNE),将一个单词及其上下文可视化到一个更低的维度空间(2D或3D)。

这非常酷,但词嵌入在预测新闻类别这样的任务上有何裨益呢?词向量可以作为神经网络的权重。具体是这样的:

首先,将语料转化为单词id的填充(padded)序列,得到一个特征矩阵。

然后,创建一个嵌入矩阵,使id为N的词向量位于第N行。

最后,建立一个带有嵌入层的神经网络,对序列中的每一个词都用相应的向量进行加权。

还是从特征工程开始,用 tensorflow/keras 将 Word2Vec 的同款预处理语料(n-grams 列表)转化为文本序列的列表:

特征矩阵X_train的尺寸为34265×15(序列数×序列最大长度)。可视化一下是这样的:

特征矩阵(34 265 x 15)

现在语料库中的每一个文本都是一个长度为15的id序列。例如,如果一个文本中有10个词符,那么这个序列由10个id和5个0组成,这个0这就是填充元素(而词表中没有的词其id为1)。我们来输出一下看看一段训练集文本是如何被转化成一个带有填充元素的词序列:

记得在测试集上也要做这个特征工程:

X_test (14,697 x 15)

现在我们就有了X_train和X_test,现在需要创建嵌入矩阵,它将作为神经网络分类器的权重矩阵.

这段代码生成的矩阵尺寸为22338×300(从语料库中提取的词表长度×向量维度)。它可以通过词表中的词id。

终于要建立深度学习模型了! 我门在神经网络的第一个Embedding层中使用嵌入矩阵,训练它之后就能用来进行新闻分类。输入序列中的每个id将被视为访问嵌入矩阵的索引。这个嵌入层的输出是一个 包含输入序列中每个词id对应词向量的二维矩阵(序列长度 x 词向量维度)。以 "我喜欢这篇文章(I like this article) "这个句子为例:

我的神经网络的结构如下:

一个嵌入层,如前文所述, 将文本序列作为输入, 词向量作为权重。

一个简单的Attention层,它不会影响预测,但它可以捕捉每个样本的权重, 以便将作为一个不错的解释器(对于预测来说它不是必需的,只是为了提供可解释性,所以其实可以不用加它)。这篇论文(2014)提出了序列模型(比如LSTM)的Attention机制,探究了长文本中哪些部分实际相关。

两层双向LSTM,用来建模序列中词的两个方向。

最后两层全连接层,可以预测每个新闻类别的概率。

现在来训练模型,不过在实际测试集上测试之前,我们要在训练集上划一小块验证集来验证模型性能。

Nice!在某些epoch中准确率达到了0.89。为了对词嵌入模型进行评估,在测试集上也要进行预测,并用相同指标进行对比(评价指标的代码与之前相同)。

该模式的表现与前一个模型差不多。 其实,它的科技新闻分类也不怎么样。

但它也具有可解释性吗? 是的! 因为在神经网络中放了一个Attention层来提取每个词的权重,我们可以了解这些权重对一个样本的分类贡献有多大。所以这里我将尝试使用Attention权重来构建一个解释器(类似于上一节里的那个):

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20200930A0458B00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券