手把手:自然语言处理太难?按这个套路走,就是砍瓜切菜!(附Python代码)

简介:

豆瓣水军检测、《权游》续写、越来越神的谷歌翻译......

最近自然语言处理(NLP)的各路应用可是被玩得风生水起。

这些NLP应用看起来炫酷到没道理,但其实背后的原理并不难理解。

今天,文摘菌就来扒一扒最常用的自然语言处理技巧和模型,手把手教你做一个简单神奇的小应用。

不吹不黑,90%的NLP问题都能用类似方法解决。

今天这个教程从数据处理的三大阶段教你自然语言处理:

  • 收集,准备、检查数据
  • 建立简单的模型(包括深度学习模型)
  • 解释、理解你的模型

整篇教程的Python代码都在这儿啦:

https://github.com/hundredblocks/concrete_NLP_tutorial/blob/master/NLP_notebook.ipynb

赶紧开始吧!

第1步:收集数据

自然语言数据的来源太多啦!淘宝评论、微博、百度百科等等。

不过今天呢,我们要处理的数据集来自推特“社交媒体上的灾难”数据集(Disasters on Social Media dataset)。

我们将使用由CrowdFlower慷慨提供的一个名为“社交媒体灾难”的数据集。该数据集由一万多条与灾难有关的推特组成。

其中一部分推特确实描述了灾难事件,而剩下的则是影评、笑话等等奇怪的东西=。=

我们的任务将是检测哪些推文是关于一个灾难性的事件,而不是一个不相关的话题,如电影。为啥要这么做呢?有关部门就可以用这个小应用及时得到灾难事件信息了嘛!

接下来,我们将把有关灾难的推特称为“disaster”,并将其他推文称为“irrelevant”。

Labels标签

注意哦,我们用的是有标签的数据。正如NLP大神Socher所说,与其花一个月用无监督学习处理一堆没有标记过的数据,还不如花个一周时间标记一点数据,整一个分类器。

6c423d7eee31aae6cfe116e3defaf872635b9e10

第2步:清洗数据

我们遵循的第一原则是:“再好的模型也拯救不了shi一样的数据”。所以,先来清洗一下数据吧!

我们做以下处理:

1. 删除所有不相关的字符,如任何非字母数字字符

2. 通过文本分隔分成单独的单词来标记你的文章

3. 删除不相关的字词,例如“@”推特或网址

4. 将所有字符转换为小写字母,以便将诸如“hello”,“Hello”和“HELLO”等单词看做相同单词

5. 考虑整合拼写错误或多种拼写的单词,用一个单词代表(例如“cool”/“kewl”/“cooool”)相结合

6. 考虑词形还原(把“am”,“are”,“is”等词语缩小为“be”这样的常见形式)

按照这些步骤并检查其他错误之后,我们可以开始使用干净的标记数据来训练模型!

第3步:找到一个好的数据表示方式

数据清理完了,我们还得把这些文字转换成数值——这样机器才看得懂嘛!

例如,在图像处理中,我们就需要把图片转换成一个表示像素点RGB强度数字矩阵。

417280799339cc58234d125bf27fa4d7499b4293

一个笑脸代表着一个数字矩阵

自然语言处理中的表示稍微复杂一点。我们会尝试多种表示方法。

独热编码(词袋)

表示计算机文本的一种自然方法是将每个字符单独编码为一个数字(例如ASCII)。

例如,我们可以建立数据集中所有唯一字的词汇表,并将唯一索引与词汇表中的每个单词相关联。然后,每个句子都被表示为一个与我们词汇表中唯一字数量一样长的列表。在这个列表中的每个索引处,我们标记给定词语出现在我们句子中的次数。这就是所谓的词袋模型,因为它是一个完全忽略我们句子中单词顺序的表现形式。如下所示。

1db1a2f691214c8dd22fdfc8604cb0b369a28e6e

代表句子作为一个词袋。左边为句子,右边是其表示形式。向量中的每个索引代表一个特定的词

可视化嵌入

在“社交媒体的灾难”这个例子中,我们有大约2万字的词汇,这意味着每个句子都会被表示为一个长度为2万的向量。该向量将包含大部分0,因为每个句子只包含我们词汇的一个很小的子集。

为了了解我们的表示是否捕获与我们的问题相关的信息(即推文是否与灾难有关),让我们将它们可视化并查看这些类是否看起来很好地分离是一个好主意。由于词汇通常非常大,并且不可能在20,000维度上显示数据,所以像PCA这样的技术将有助于将数据投影到两个维度。如图所示:

844eda3b790ee405ded95f70f56525a604ffc807

可视化

这两类看起来不太好分开,这可能是我们嵌入的一个特征,或者仅仅是由于我们的维度降低。为了看看词袋特征是否有用,我们可以根据它们来训练一个分类器。

第4步:分类

首先遇到问题时,一般的最佳做法是从最简单的工具开始解决问题。每当涉及到对数据进行分类时,基于通用性和可解释性的一个普遍喜好是Logistic回归。训练非常简单,结果可以解释,因为你可以轻松地从模型中提取最重要的系数。

我们将数据分成一个用于拟合模型的训练集和一个用于评估模型泛化能力的测试集,以此来推广到不可见的数据。训练结束后,我们得到了75.4%的准确度。还不错哦!如果我们简单地猜测最频繁的类(“irrelevant”),准确率只能达到57%。但是,即使75%的精度足够满足我们的需求,我们也不应该在不尝试了解它的情况下,发布一个模型。

第5步:检查

混淆矩阵

第一步是了解我们模型的错误类型,以及哪种类型的错误是最不可取的。在我们的例子中,假阳性划分为irrelevant,事实上是diasaster,而假阴性实际是disaster,而归类为irrelevant。如果要优先处理每一个潜在的事件,我们会想要降低我们的假阴性。然而,如果我们受到资源的限制,我们可能会优先考虑较低的假阳性来减少误报。 将这些信息可视化的一个好方法是使用混淆矩阵,它将我们的模型的预测与真实标签进行比较。理想情况下,矩阵将是从左上角到右下角的对角线(预测和实际完美匹配)。

d974940a6befaaf1c5522ea17eda45613078f3fe

混淆矩阵(绿色是高,蓝色是低)

相对于假阳性来说,我们的分类器按比例产生更多的假阴性。换句话说,我们模型最常见的错误是将disaster归类为irrelevant。如果假阳性导致高的执法成本,这使我们的分类器可以有一个很好的bias(偏差)。

模型解析

为了对我们的模型进行验证并分析它预测的准确性,我们需要看它通过使用哪些词来做决定,这是十分重要的。如果我们的数据存在偏差,那么分类器将只能在样本数据中做出准确预测,而这个模型在现实世界中则不能很好地推广。在此,我们分别为disaster和irrelevant绘制了“最关键的词”的表。由于我们可以对用于预测的模型的系数进行提取和排序,使用词袋和逻辑回归来计算单词的重要性其实很简单。

2ebb84f3f2a1f4346180be4a50533f9705c31fe1

词袋:关键词

我们的分类器正确地采取了一些模式(如hiroshima广岛、massacre大屠杀),但这其中也显然有一些看似无意义的过度拟合(heyoo蓝调摇滚,x1392话题简称)。现在,我们的词包模型正在处理包含各种不同单词的巨大词汇表,并且平等地对待所有单词。然而,这其中的一些词语出现的非常频繁,只会对我们的预测产生影响。接下来,我们将尝试一种新方法来表示能够统计单词频率的句子,看看能否从我们的数据中获取更多的信号。

第6步:统计词汇结构

为了使我们的模型更多的专注于有意义的单词,我们可以在词袋模型顶部使用TF-IDF评分(术语频率、逆文档频率)。TF-IDF通过在数据集中的出现频率来确定词权重,减少出现过于频繁的词的权重而增加到噪音干扰上。下图是对我们新嵌入数据的PCA预测。

de72a6616389677bdedf5f74a60fed8c5b2a0bd0

TF-IDF嵌入可视化

从上图可以看出,在这两种颜色之间有一个相对清晰的分界。这将会使我们的分类器更容易将其分为两组。让我们来看看这是否会带来更好的表现吧!接下来在我们新嵌入的数据上训练另一个Logistic回归参数,我们得到了76.2%的准确性。

这是一个非常细微的改进。我们的模型是否已经开始采用更关键的词?如果我们在防止我们模型“作弊”的同时取得了更好的效果,那么我们就可以真正认为这个模型实现了一次突破了。

db85e7822a4a87d062b9af21ba3753ee8bb87608

TF-IDF:关键词

模型所采取的词看起来更相关!尽管我们测试集的指标只是略有增加,但是我们对模型使用的术语将会更有信心,所以将其应用在与客户交互的系统中会感到更加舒适。

第7步:巧妙利用语义

将词转化为向量

我们的最新模型设法采取具有高信号的词。然而,如果我们配置这个模型,很可能会遇到我们之前在训练集中没有看到的词。然而即使在训练中看到非常相似的单词,以前的模型也不能准确辨别这些干扰。

为了解决这个问题,我们需要捕捉词的语义,这意味着我们需要理解“好”和“积极”等词比“杏”和“大陆”更相近。我们将用名为Word2Vec这个工具帮助我们捕捉语义。

使用预训练的词

Word2Vec是一种实现连续词嵌入的技术。它通过阅读大量的文字来学习,并记忆哪些词倾向于出现在相似的语境中。在训练足够多的数据后,它会为词汇表中的每个词生成一个300维的向量,意思相近的词彼此则会更接近。

本文的作者开源了一个模型,它在一个非常庞大的语料库上预先训练好,我们可以利用这个语料库将一些语意知识纳入到我们的模型中。预训练的向量可以在与这篇文章相关的知识库中找到。

句级表示

为我们的分类器获得句子嵌入的一个快速方法是:平均句中所有词的Word2Vec得分。这跟以前一样也是一个词袋的方法,但是这次我们只丢掉句子的语法,而保留一些语意信息。

58d953cbc356babd075d3ccf729e34b0b3a42be8

Word2Vec句嵌入

下图是使用先前技术获得的新嵌入可视化:

fb6b9fcd36f7068e226dd8f5a8dbbc6f80ee07b2

Word2Vec嵌入可视化

两组颜色的分界看起来更加明显,我们的新嵌入技术一定能帮助我们的分类器找到两个类之间的分离。第三次(使用Logistic回归)训练同一个模型后,我们得到了77.7%的精准度,这是我们到目前为止得到的最好的结果!接下来该检查我们的模型了。

复杂性与可解释性的权衡

由于新嵌入技术没有像我们以前的模型那样以每个单词一维向量来表示,所以很难看出哪些单词与我们的分类最为相关。虽然我们仍能使用Logistic回归的系数,但它们只与我们嵌入的300维度相关,而与词汇索引没有关联。

对于如此低的准确度,失去所有可解释性似乎是一个艰难的权衡。然而,对于更复杂的模型,我们可以利用LIME等黑盒解释器来深入了解分类器的工作原理。

Github通过开源软件包提供LIME。黑盒解释器允许用户通过干扰输入(在我们例子中即去除句子中的单词)来解释任何分类器的决定,并查看预测的变化。

接下来让我们一起看看我们数据集中的几个句子的解释。

17142966be7a04d741b86f70e5dbd6822e9b6236

然而,我们并没有时间去探索数据集中的数千个案例。我们应该做的则是在测试案例的典型范例上继续运行LIME,看看哪些词的占有率仍能位居前列。通过这种方法,我们可以获得像以前模型那样的单词的重要性分数,并验证模型的预测。

a802999fd6e835463c569ee280468ada5ae0177e

Word2Vec:关键字

模型似乎能提取高度相关的词,这意味着它也许能做可理解的决定。而这些看起来像是以前所有模型中最相关的词,因此我们更愿意将其配置到实际操作中。

第8步:使用端到端的方法来巧妙利用语义

我们已经介绍了快速有效的方法来生成紧凑的句嵌入。然而,通过省略词序,我们放弃了句子的所有句法信息。如果这些方法不能提供充分的结论,则可使用更复杂的模型,将整个句子作为输入并预测标签,而不需要建立中间表示。一种常见的方法是将句子作为一个词向量序列,使用Word2Vec或更新的方法,如GloVe或CoVe。这就是我们将在下面做的。

8e05790e850cd8c1d369ad35642cf1127a898294

高效的端到端体系结构(源)

用于句子分类的卷积神经网络训练非常迅速,并且作为入门级的深度学习体系能够很好地完成任务。虽然卷积神经网络(CNN)主要因其在图像数据上的性能而闻名,但它们早已在文本相关任务上提供了优异的结果,并且通常比大多数复杂的NLP方法(例如LSTM和编码器/解码器体系结构)能更快地训练。这个模型保留了词序,并且学习了关于哪些词序列可以预测我们目标类的有价值的信息。与之前的模式相反,它是可以区分“亚历克斯吃植物”和“植物吃亚历克斯”的不同。

训练这个模型不仅不需要比以前方法更多的工作(详见代码),而且给了我们一个比以前方法更好的模型,准确率达到了79.5%!与上述模型一样,下一步应该是继续使用我们描述的方法来进行探索和解释预测,以验证它确实是配置给用户的最佳模型。现在,你应该能自己上手处理这个问题了。

小结

  • 从一个简单快捷的模型开始
  • 解释其预测
  • 了解它正在犯的错误类型
  • 利用这些知识来确定下一步工作:模型对数据是否有效,还是应该使用更为复杂的模型

这些方法被应用于特定的案例,如理解和利用诸如推文之类的短文本模型,但实际上这些思想广泛地适用于各种问题哦!

就像开头文摘菌说的,90%的自然语言处理问题都可以用这个套路解决,那还不是砍瓜切菜!


原文发布时间为:2018-02-28

本文作者:文摘菌

本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“大数据文摘”微信公众号

相关文章
|
10天前
|
监控 Python
Python中的装饰器:提升代码灵活性与可读性
在Python编程中,装饰器是一种强大的工具,能够提升代码的灵活性和可读性。本文将介绍装饰器的基本概念、使用方法以及实际应用场景,帮助读者更好地理解和利用这一功能。
|
12天前
|
人工智能 数据可视化 数据挖掘
【python】Python航空公司客户价值数据分析(代码+论文)【独一无二】
【python】Python航空公司客户价值数据分析(代码+论文)【独一无二】
|
17天前
|
数据采集 JSON 数据可视化
【python】python懂车帝数据可视化(代码+报告)
【python】python懂车帝数据可视化(代码+报告)
|
16天前
|
机器学习/深度学习 算法 搜索推荐
Machine Learning机器学习之决策树算法 Decision Tree(附Python代码)
Machine Learning机器学习之决策树算法 Decision Tree(附Python代码)
|
11天前
|
缓存 监控 算法
优化Python代码性能的10个技巧
提高Python代码性能是每个开发者都需要关注的重要问题。本文将介绍10个实用的技巧,帮助你优化Python代码,提升程序的运行效率和性能表现。无论是避免内存泄漏、减少函数调用次数,还是使用适当的数据结构,都能在不同场景下发挥作用,使你的Python应用更加高效稳定。
|
2天前
|
机器学习/深度学习 自然语言处理 算法框架/工具
用于NLP的Python:使用Keras进行深度学习文本生成
用于NLP的Python:使用Keras进行深度学习文本生成
15 2
|
2天前
|
数据安全/隐私保护 Python
Python中的装饰器:提升代码可读性与灵活性
Python中的装饰器是一种强大的工具,可以在不改变函数原有逻辑的情况下,为函数添加额外的功能。本文将介绍装饰器的基本概念和用法,并通过实例演示如何利用装饰器提升代码的可读性和灵活性,使代码更加简洁、易于维护。
|
3天前
|
BI 开发者 数据格式
Python代码填充数据到word模板中
【4月更文挑战第16天】
|
5天前
|
缓存 算法 Python
优化Python代码的十大技巧
本文介绍了十种优化Python代码的技巧,涵盖了从代码结构到性能调优的方方面面。通过学习和应用这些技巧,你可以提高Python程序的执行效率,提升代码质量,以及更好地应对复杂的编程任务。
|
5天前
|
程序员 Python
Python中的装饰器:提升代码可读性与灵活性
在Python编程中,装饰器是一种强大的工具,可以在不修改原始代码的情况下,动态地添加功能。本文将深入探讨Python中装饰器的原理、用法和实际应用,以及如何利用装饰器提升代码的可读性和灵活性。