如何解决 90% 的 NLP 问题:分步指南

avatar
阿里巴巴 前端委员会智能化小组 @阿里巴巴

译 / 星与


文本数据无处不在


无论您是一家老牌公司还是在推出一项初创服务,您都可以始终利用文本数据来验证,改善和扩展产品的功能。从文本数据中提取含义和进行学习的科学是被称为自然语言处理(NLP)。


NLP每天都会产生令人兴奋的新结果。与数多家公司合作之后,Insight团队发现一些频繁出现的主要的实际应用场景。


  • 识别不同的用户群(例如,预测客户流失、终身价值、产品偏好)
  • 准确地检测和提取不同类别的反馈(正面和负面评价/意见,提取特定属性,如衣服尺寸/合身度…)
  • 预测文本的意图(例如请求基本帮助、紧急问题)


虽然网上有许多NLP论文和教程,但我们发现很难找到如何从一开始就有效解决这些问题的指导方针和技巧。



这篇文章的作用


在每年进行的大量项目和汲取的建议和经验之后,我们写了这篇文章来解释如何构建机器学习解决方案来解决上述问题。我们将从最简单的可行方法开始,然后继续讨论更细微的解决方案,如特征工程、词向量和深度。阅读之后你应该可以:


  • 收集、准备和检查数据
  • 建立简单的模型开始,必要时过渡到深度学习
  • 解释并理解你的模型,以确保你确实获取到了有效的信息而不是噪声


我们写这篇文章作为一个循序渐进的指南;它也可以作为一个高效方法的概述指导。除此之外这篇文章还附有一个互动笔记本(ipython notebook),演示和应用所有这些技术。请自由使用运行这些代码进行实践!



Step 1:收集数据



示例数据源


每一个机器学习问题都是从数据开始的,比如电子邮件、帖子或推特的列表。文本信息的常见来源包括:


  • 产品评论(亚马逊、Yelp和各种应用商店)
  • 用户原创内容(Tweets、Facebook帖子、StackOverflow问题)
  • 问题解决(用户诉求、相关票证、聊天日志)



“社交媒体上的灾难(Disasters on Social Media)”数据集


在本文中,我们将使用Figure Eight慷慨提供的数据集,称为“社交媒体上的灾难”,其中:


贡献者查看了10000多条经过各种搜索的推文,如“燃烧”、“隔离”和“混乱”,然后识别这些推文是否指灾难事件(而不是用这个词开玩笑或电影评论或其他非灾难性的东西)。


我们的任务是检测哪些tweet是关于灾难性事件的,而不是无关的电影评论。为什么?一个可进行应用的场景是,向执法人员通报紧急情况,而忽略对最近亚当·桑德勒电影的评论。这项任务的一个特殊挑战是,这两类内容都包含用于查找tweets的相同关键词词,因此我们必须使用更细微的差异来区分它们。


在这篇文章的接下来的部分,我们将把关于灾难的tweets称为“灾难”,将关于其他任何事情的tweets称为“无关”。



数据标记


我们已经标记了数据,因此我们知道哪些tweets属于哪些类别。正如Richard Socher在概述的,找到和标记足够的数据来训练模型通常比试图优化复杂的无监督方法更快、更简单、成本更低。



Step 2:清洗数据


我们遵循的第一条规则是:“你的模型不会比你的数据更好。”


数据科学家的一项关键技能是知道下一步是处理模型还是数据。一个好的经验法则是先看数据,然后再清理它。一个干净的数据集将允许模型学习有意义的特征,而不是过度适应不相关的噪声。


下面是用于清理数据的检查表:(有关详细信息,请参见代码):


  1. 删除所有不相关的字符,如任何非字母、数字、中文的字符
  2. 令牌化(Tokenize):将文本分割成单独的词语
  3. 删除不相关的词,例如twitter中的“@”或ur
  4. 将所有字符转换为小写,以便将“hello”、“hello”和“hello”等词语视为相同的含义
  5. 考虑将拼写错误或重复拼写的单词组转成一个表示(例如“cool“/”kewl“/”coool“)
  6. 考虑引理化(lemmatization)(将“am”、“are”和“is”之类的词简化为诸如“be”之类的常见形式)


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



Step 3:找到一个好的数据表示形式


机器学习模型以数值为输入。例如,处理图像的模型采用表示每个颜色通道中每个像素强度的矩阵。



我们的数据集是一个句子集合,因此为了让我们的算法从数据中提取模式,我们首先需要找到一种方法,让我们的算法能够理解的方式来表示它,即转换为一个数字集合的表示。



词袋模型(Bag of Words)


表示计算机文本的一种自然方法是将每个字符单独编码为一个数字(例如ASCII)。如果我们将这个简单的表示形式输入到分类器中,它将不得不根据我们的数据从头学习单词的结构,这对于大多数数据集来说是不可能的。我们需要用更高层次的方法。


例如,我们可以构建数据集中所有词语的词表,并关联每个词语的唯一索引。然后,每个句子都被表示为一个列表,它的长度与我们词表中不同单词的数量相同。在这个列表中的每个索引处,我们标记给定单词在句子中出现的次数。这被称为词袋模型(完全忽略了句子中单词的顺序)。如下所示。


词袋模型表示句子。图中句子在左边,表示在右边。向量中的每个索引表示一个特定的词。



单词嵌入(embeddings)可视化


在“社交媒体灾难”的例子中,我们的词表中大约有20000个单词,这意味着每一个句子都将被表示为长度为20000的向量。向量中主要包含‘0’,因为每个句子只出现词表中一小部分词语。


为了查看我们的嵌入是否捕获了与我们的问题相关的信息(即tweets是否与灾难有关),最好将它们可视化,并查看不同类之间的分隔是否良好。由于词汇表通常非常庞大,不可能在20000维中可视化数据,因此主成分分析(PCA)等技术将有助于将数据投影到二维。如下面这张图。



这两个类看起来并没有很好地分离,这可能是我们嵌入的方式导致的一个特征,也可能只是我们维度缩减导致的一个特征。为了验证词袋模型特征是否有用,我们可以先用这些数据来训练分类器。



Step 4: 分类


一开始处理一个问题时,一般的最佳实践是从能够处理这项任务的最简单的工具开始。每当涉及到数据分类时,逻辑回归( Logistic Regression)是一种通用性和可解释性很强的常用方法。这这个方式是训练非常简单并且结果是可以解释的,因为你可以很容易地从模型提取到最重要的参数、系数。


我们将数据分为一个训练集和一个测试集,分别用来训练模型和测试模型效果,测试集用来查看它对未看到的数据的泛化程度。经过训练,我们得到了75.4%的准确率。效果还不错!如果全部猜测最频繁出现的类(“无关”)只有57%。然而,即使75%的精度足以满足我们的需求,但是我们还是需要在尝试理解模型之后,再做模型的部署使用。



Step 5: 检查



混淆矩阵(Confusion Matrix)


第一步是了解我们的模型产生的错误类型,以及哪种错误是最不应该出现的。在我们的示例中,误报的正例是将“无关”的tweet预测为灾难,而误报的反例是将“灾难”的tweet预测为“无关”。如果我们的首要任务是对每一个潜在的事件做出反应,我们会希望降低我们误报的反例。但是,如果我们在资源上受到限制,我们可能会优先考虑较低的误报的正例率,以减少误报带来的资源消耗。可视化这些信息的一个好方法是使用一个混淆矩阵,它将我们的模型做出的预测与真实的标签进行比较。理想情况下,矩阵的分布是从左上角到右下角的对角线(我们的预测完全符合事实)。

我们的分类器产生的假阴性比假阳性多(按比例)。换句话说,我们的模型最常见的错误是错误地将灾难分类为无关的。如果假阳性代表了执行的高成本,这可能是我们模型的一个较好的偏差特性。



解释我们的模型


为了验证我们的模型并解释它的预测,一个重要的方面是,看看它是根据什么词来做预测的是。如果我们的数据是有偏差的,那么我们的模型会在样本数据中做出准确的预测,但是在现实的场景中不会有很好表现。在这里,我们为灾难类和无关类绘制权重最高的单词。用词袋和Logistic回归来绘制单词重要性很简单,因为我们只需提取模型用于预测的系数并对其进行排序。


我们的模型正确地提取了一些模式(广岛,大屠杀),但显然似乎在一些无意义的术语(heyoo,x1392)上过拟合。现在,我们的词袋模型处理大量不同单词的词汇,并平等地处理所有单词。然而,这些词中有一些出现非常频繁,但只会给我们的预测带来噪声。接下来,我们将尝试用一种能够展现单词频率方法来表示的句子,看看我们能否从数据中提取更多的信息。



Step 6: 词表的统计结构



TF-IDF


为了帮助我们的模型更加关注有意义的词语,我们可以在我们的词袋模型上使用TF-IDF分数(术语频率,文档反向频率)。TF-IDF根据单词在我们的数据集中的稀有程度来衡量单词,对过于频繁且只会增加噪声的词语进行降权。下面这是我们新的主成分分析嵌入输入的图像。



我们可以看出这两种颜色之间有更清楚的分布区别。这将使我们的模型更容易分离这两个类别。让我们看看这是否会带来更好的表现。在新的嵌入数据上训练另一个逻辑回归,我们达到了76.2%的准确率。


稍有改善。我们的模型是否已经开始学习更重要的单词?如果我们在防止模型“作弊”的同时获得更好的结果,那么我们就可以真正地将此模型视为一种有效的改进。



它所选用的重要的词语看起来更有意义!尽管我们在测试集上的准确率指标只略有增加,但我们对模型新使用的词语有更自信,因此在面向用户的系统中部署它会感觉更合适。



Step 7: 使用语义



Word2Vec


我们的最新的模型设法接收更有意义的词语。但是,如果我们部署这个模型,很可能会遇到以前在我们的训练集中没有看到的单词。之前的模型将无法准确地对这些没有见过的推文进行预测,即使它在训练期间看到了非常相似的词语。


要解决这个问题,我们需要捕获单词的语义,这意味着我们需要理解像“好的”和“积极的”这样的单词比“杏”和“大陆”的含义更相近,我们将用来帮助我们捕获语义的工具叫做Word2Vec。



使用预训练过的词语


Word2Vec是一种寻找单词嵌入连续性的技术。它通过阅读大量的文本和记忆在相似的上下文中出现的单词来学习。在经过足够的数据训练后,它为词汇表中的每个单词生成一个300维向量,具有相似含义的单词彼此在向量空间中更接近。


这篇论文的作者开源了一个模型,该模型是在一个非常大的语料库上预训练过的,我们可以利用这个语料库将一些语义知识包含到我们的模型中。可以在与论文相关联的仓库中找到预先训练过的向量。



句子级表示


为我们的模型生成句子级嵌入的一个快速方法是平均我们句子中所有单词的Word2Vec数字。这是一个像之前一样的词袋方法,但是这次我们保留了一些语义信息,只丢失了句子的语法。



下面是使用先前提到的技术新生成嵌入的可视化:



这两组颜色在这里看起来更加分离,我们的新嵌入应该帮助我们的模型找到两个类之间的分离特征。第三次训练同一个模型(逻辑回归)后,我们达到了77.7%的准确率,这是我们迄今为止最好的成绩!是时候检查我们的模型了。



复杂性/可解释性权衡


由于我们的嵌入并不像之前的模型那样用每个单词一个维度的向量来表示,所以很难看出哪个单词与我们的模型最相关。虽然我们仍然可以获得逻辑回归系数,但它们与嵌入的300个维度有关,而不是只与单词的索引有关。


对于如此低的准确性提升,而失去所有可解释性似乎是一个严酷的权衡。然而,对于更复杂的模型,我们可以利用诸如LIME这样的黑盒解释程序来了解我们的模型是如何工作的。



LIME


LIME是Github上提供了一个开源软件。一个允许用户通过改变输入(在我们的例子中,从句子中删除单词)并查看预测如何变化的黑盒解释程序,来解释每个类别对一个特定示例的决策过程。


让我们看看对数据集中句子的一些解释。



被挑选出来归类为“相关”的灾难词



在这个例子里,单词对分类的贡献似乎不太明显


然而,我们没有时间去探索数据集中的成千上万的例子。相反,我们要做的是在一个有代表性的测试用例样本上运行LIME,看看哪些单词会成为强有力的贡献者。使用这种方法,我们可以得到单词重要性的分数,就像我们之前的模型一样,用来验证我们的模型的预测,下面是使用Word2Vec的词语重要性图表。




Step 8:使用端到端的实现来利用语法信息


我们已经介绍了快速有效地生成句子级嵌入的方法。然而,忽略了单词的顺序,我们丢弃了句子的所有句法信息。如果这些方法不能提供有效的模型结果,可以使用更复杂的模型,将整个句子作为输入并预测标签,无需构建中间产物作为数据表示。常用的方法是使用Word2Vec或更新的模型(如GloVeCoVe)将句子表示为词词语向量的序列。这就是我们下面要做的。



高效的端到端架构(来源


用于句子分类的卷积神经网络训练速度非常快,工作良好,是一种入门级的深度学习体系结构。虽然卷积神经网络(CNN)主要以其在图像数据上的表现而闻名,但它们在文本相关的任务上也一直有优异的效果,并且通常比大多数复杂的NLP方法(例如LSTMs和[编解码器架构](https://www.tensorflow.org/tutorials/seq2seq)训练快得多。该模型保留了词语的顺序信息,并从中学习到有价值的信息,用于预测我们的目标类。与之前的模型不同点在于,它可以区分“Alex吃植物”和“植物吃Alex”


训练这个模型和之前的方法相比不需要太多的前置工作(详见代码),并且获得了一个目前最优的模型,达到了79.5%的准确率!与之前的模型一样,下一步应该是使用我们描述的方法来探索和解释预测结果,以验证它确实是可以向用户部署的最佳模型。到现在为止,你应该可以处理比较合理地解决这个灾害预测问题。



最后总结


下面是我们这篇文章成功使用的方法的简要概述:


  • 从一个简单快捷的模型开始
  • 解释它的预测
  • 了解它所犯的错误
  • 使用这些知识来指导你下一步的工作,无论是处理数据还是更复杂的模型。


虽然提到的这些方法被应用到一个特定的例子中,使用了专门为理解和利用短文本(如tweets)而定制的模型,但是这些思想广泛适用于各种问题。我希望这对你有所帮助。


原文


blog.insightdatascience.com/how-to-solv…