利用机器学习方法来理解和利用文本,从最简单的到state-of-the-art,由浅入深,循序渐进。
文本数据到处都是
无论是一家已成立的公司,还是正在开发一项新服务,都可以利用文本数据来验证、改进和扩展产品的功能。从文本数据中提取语义和学习的科学是一个被称为自然语言处理(NLP)的活跃研究课题。
NLP每天都有新的重要的进展,这是一个非常大的领域。然而,在与数百家公司合作之后,Insight团队发现一些关键的实际应用比其他应用出现得更频繁:
虽然在网上有许多NLP的论文和教程,但我们发现很难找到指导方针和技巧来从根本上有效地解决这些问题。
这篇文章有什么用?
在一年领导了数百个项目,并从美国各地的顶级团队获得建议之后,我们写了这篇文章来解释如何构建机器学习解决方案来解决上述问题。我们将从最简单可行的方法开始,然后转向更细微的解决方案,如特征工程、词向量和深度学习。
读完这篇文章,你会知道:
我们写这篇文章是作为一个循序渐进的指南,它还可以作为高效标准方法的高层次概述。
第一步: 收集数据
数据源的样例
每一个机器学习问题都是从数据开始的,比如电子邮件、帖子或tweet列表。常见的文本信息来源包括:
“Disasters on Social Media” dataset
“社交媒体灾难”数据集
对于本文,我们将使用图8提供的数据集,名为“社交媒体上的灾难”,其中:
贡献者们查看了1万多条推文,这些推文都经过了各种各样的搜索,比如“着火”、“隔离”和“混乱”,然后指出这条推文是否指的是灾难事件(而不是带有这个词的笑话、电影评论或其他非灾难性的东西)。
我们的任务是检测哪些tweet是关于灾难性事件的,而不是与之相关的主题,比如电影。为什么?一种潜在的应用可能是,在不理会对Adam Sandler最新电影的评论的情况下,只向执法官员通报紧急情况。这项任务的一个特殊挑战是,这两个类都包含用于查找tweet的相同搜索词,因此我们将不得不使用更细微的差异来区分它们。
在本文的其余部分,我们将把关于灾难的tweet称为“灾难”,而关于其他任何事情的tweet称为“无关”。
标签
我们已经标记了数据,所以我们知道哪些tweet属于哪些类别。正如Richard Socher在下面所概述的,找到和标记足够的数据来训练模型通常更快、更简单、更便宜,而不是试图优化一个复杂的无监督方法。
第二步: 数据清洗
我们遵循的第一条规则是:“你的模型永远只会和你的数据一样好。”
数据科学家的关键技能之一是知道下一步应该是处理模型还是数据。一个好的经验法则是先查看数据,然后整理它。一个干净的数据集将允许模型学习有意义的特征,而不会在不相关的噪声上过拟合。
这里有一个清单,可以用来清理你的数据:
在遵循这些步骤并检查其他错误之后,我们可以开始使用干净的、有标记的数据来训练模型!
第三步:找一个好的数据表示
机器学习模型以数值作为输入。例如,处理图像的模型采用矩阵表示每个颜色通道中的每个像素的强度。
用数字矩阵表示的笑脸
我们的数据集是一个句子列表,所以为了让我们的算法从数据中提取模式,我们首先需要找到一种方法,以我们的算法能够理解的方式来表示它,即作为一个数字列表。
One-hot编码(词袋)
表示计算机文本的一种自然方法是将每个字符单独编码为一个数字。如果我们要将这个简单的表示形式提供给分类器,那么它就必须仅基于我们的数据从零开始学习单词的结构,这对于大多数数据集来说是不可能的。我们需要使用更高层次的方法。
例如,我们可以为数据集中所有惟一的单词构建一个词汇表,并为词汇表中的每个单词关联一个惟一索引。然后,每个句子都被表示为一个列表,这个列表与我们词汇表中不同单词的数量一样长。在这个列表的每个索引处,我们标记给定单词在我们的句子中出现的次数。这称为词袋模型,因为它是一个完全忽略句子中单词顺序的表示。如下图所示。
把句子表示成词袋。左边是句子,右边是描述。向量中的每个索引表示一个特定的单词。
嵌入的可视化
在“社交媒体灾难”的例子中,我们的词汇量大约有20000个单词,这意味着每个句子都将被表示为一个长度为20000的向量。向量中大部分都是0,因为每个句子只包含词汇表的一个非常小的子集。
为了查看我们的嵌入是否捕获了与我们的问题关的信息(即tweet是否与灾难有关),将它们可视化并查看类之间是否有很好的分隔是一个好主意。由于词汇表通常非常大,并且不可能在20,000个维度中可视化数据,因此PCA等技术将帮助将数据投射到两个维度。下图所示。
词袋嵌入的可视化
这两个类看起来没有很好地分离,这可能是我们的嵌入的一个特性,或者仅仅是维数减少的一个特性。为了了解词袋特征是否有用,我们可以训练一个基于词袋特征的分类器。
第四步: 分类
当第一次处理一个问题时,一般的最佳实践是从能够解决该工作的最简单的工具开始。每当涉及到对数据进行分类时,由于其通用性和可解释性,最受欢迎的是Logistic Regression。它的训练非常简单,结果是可解释的,因为你可以很容易地从模型中提取最重要的系数。
我们将数据分成两个部分,一个是用于拟合模型的训练集,另一个是测试集,以查看它对不可见数据的泛化程度。经过训练,我们得到了75.4%的准确率。还可以!猜测出现最多的类别(“无关紧要”)只会给我们57%的答案。然而,即使75%的精度已经足够满足我们的需求,我们不能在不理解模型的情况下就发布模型。
第五步:检查
混淆矩阵
第一步是了解我们的模型所犯错误的类型,以及哪些错误是最不可取的。在我们的示例中,false positive 将不相关的tweet分类为灾难,false negative 将灾难分类为不相关的tweet。如果我们的首要任务是对每一个潜在的事件做出反应,我们就会想要降低我们的false negative 。然而,如果我们在资源上受到限制,我们可能会优先考虑较低的假阳性率,以减少虚警。将这些信息可视化的一个好方法是使用混淆矩阵,它将我们的模型做出的预测与真实的标签进行比较。理想情况下,矩阵应该是一条从左上角到右下角的对角线(我们的预测与事实完全吻合)。
混淆矩阵(绿色表示比例高,蓝色表示比例低)
我们的分类器创建的假阴性比假阳性多(按比例)。换句话说,我们的模型最常见的错误是不准确地将灾难分类为无关紧要的。如果假阳性代表执法的高成本,对我们的分类器,这可能是一个很好的偏见,。
解释我们的模型
为了验证我们的模型并解释它的预测,很重要的是看看它使用哪些词汇来做决策。如果我们的数据是有偏差的,我们的分类器会在样本数据中做出准确的预测,但是模型在现实世界中不能很好地推广。在这里,我们为灾难类和无关类绘制最重要的单词。由于我们只需要提取模型用于预测的系数并对其进行排序,因此用词袋模型和逻辑回归来绘制单词重要性图非常简单。
词袋:单词重要性
我们的分类器正确地选择了一些模式(广岛,大屠杀),但显然似乎在一些无意义的术语上过拟合(heyoo, x1392)。现在,我们的词袋模型正在处理大量不同单词的词汇,并且平等地对待所有单词。然而,其中一些词汇非常频繁,而且只会对我们的预测产生干扰。接下来,我们将尝试一种表示句子的方法来解释单词的频率,看看我们能否从数据中获取更多的信号。
第6步:词汇结构计数
TF-IDF
为了帮助我们的模型更多地关注有意义的单词,我们可以在我们的词袋模型上使用TF-IDF score (Term Frequency, Inverse Document Frequency)。TF-IDF根据单词在我们的数据集中的稀有程度来衡量单词,对过于频繁且只会增加噪音的单词进行减弱。这是我们新的嵌入的PCA投影。
TF-IDF嵌入可视化
从上面我们可以看到,这两种颜色的区别更加明显。这将使我们的分类器更容易地将两个组分开。让我们看看这是否会带来更好的性能。在我们的新嵌入上训练另一个逻辑回归,我们得到了76.2%的准确率。
非常轻微的改善。我们的模型是否开始学习更重要的单词?如果我们在防止模型“作弊”的同时获得了更好的结果,那么我们就可以真正地将该模型视为一个升级。
TF-IDF: 单词重要性
选到到的单词看起来更相关了!尽管我们测试集上的准确率只增加了一点点,但是我们对我们的模型所使用的术语有了更多的信心,因此在一个与客户交互的系统中部署它会更舒服。
第7步:语义的威力
Word2Vec
我们最新的模型能够识别高频词。然而,如果我们部署这个模型,很有可能会遇到以前在我们的训练集中没有见过的单词。之前的模型不能准确地对这些tweet进行分类,即使在训练期间看到了非常相似的单词。
为了解决这个问题,我们需要捕捉单词的语义,这意味着我们需要理解像“good”和“positive”这样的单词要比“apricot”和“continent”更接近。我们用来帮助我们捕捉语义的工具叫做Word2Vec。
使用预训练的单词
Word2Vec是一种为单词寻找连续嵌入的技术。它通过阅读大量的文本和记忆在相似的语境中出现的单词来学习。在对足够的数据进行训练后,它为词汇表中的每个单词生成一个300维的向量,具有相似含义的单词彼此之间距离更近。
这篇论文的作者(https://arxiv.org/abs/1301.3781)公开了一个模型的源代码,这个模型是在一个非常大的语料库上预先训练的,我们可以利用这个语料库将一些语义知识包含到我们的模型中。可以在与本文关联的repository中找到预先训练好的向量。
语义级别的表示
为我们的分类器获得一个句子嵌入的快速方法是平均我们句子中所有单词的Word2Vec得分。这是一个词袋的方法,就像以前一样,但是这次我们只丢失了我们句子的语法,而保留了一些语义信息。
Word2Vec句子的嵌入
使用之前的技术可视化的我们的新嵌入:
Word2Vec嵌入可视化
这两组颜色在这里看起来更加分离,我们的新嵌入应该有助于我们的分类器找到这两个类之间的分离。经过第三次对同一模型的训练(Logistic回归),我们得到的准确率为77.7%,是我们目前最好的结果!是时候检查我们的模型了。
复杂性和可解释性的权衡
由于我们的嵌入不像之前的模型中那样以每个单词一维的向量来表示,所以很难看出哪些单词与我们的分类最相关。虽然我们仍然可以访问逻辑回归的系数,但它们与嵌入的300个维度有关,而不是与单词的索引有关。
对于如此低的精确度,失去所有的可解释性似乎是一个艰难的权衡。但是,对于更复杂的模型,我们可以利用黑匣子解释器,比如LIME,以便深入了解分类器的工作原理。
LIME
LIME可在Github上获得通过一个开源包。黑盒解释器允许用户通过扰动输入(在我们的例子中是从句子中删除单词)并查看预测如何变化来解释任何分类器对一个特定示例的决策。
让我们从我们的数据集中看一些句子的解释。
选择正确的灾难词汇来分类为“相关”。
在这里,单词对分类的贡献似乎不那么明显。
然而,我们没有时间研究数据集中的数千个示例。相反,我们要做的是对一个具有代表性的测试用例样本运行LIME,并查看哪些单词会不断出现,成为强大的贡献者。使用这种方法,我们可以得到单词重要性评分,就像我们之前的模型一样,并验证我们的模型的预测。
Word2Vec: 单词重要性
看起来这个模型选择了高度相关的词汇,这意味着它似乎做出了可以理解的决定。在所有之前的模型中,这些似乎是最相关的词汇,因此我们更愿意将它们部署到生产环境中。
第8步:利用语义,使用端到端的方法
我们已经介绍了生成密集的语句嵌入的快速而有效的方法。然而,通过忽略单词的顺序,我们丢弃了我们句子的所有语法信息。如果这些方法不能提供足够的结果,你可以使用更复杂的模型,它将整个句子作为输入并预测标签,而不需要构建中间表示。一种常见的方法是使用Word2Vec或更近期的方法如GloVe或CoVe将一个句子视为单个单词向量的序列。这就是我们下面要做的。
高效的端到端的结构
Convolutional Neural Networks for Sentence Classification训练非常快,是一种入门级的深度学习架构。而卷积神经网络(CNN)主要是图像数据性能著称,他们在文本相关的任务上也能提供优秀的结果。和通常最复杂的NLP训练方法(如[LSTMs]和编码器/解码器架构更快。这个模型保存单词的顺序,并学习有价值的信息,以及哪些单词序列可以预测我们的目标类。与之前的模型相反,它可以区分“Alex eats plants”和“Plants eat Alex”。
与以前的方法相比,训练这个模型并不需要更多的工作,并为我们提供了一个比以前的方法更好的模型,获得79.5%的准确率!与上面的模型一样,下一步应该是使用我们描述的方法探索和解释预测,以验证它确实是部署到用户的最佳模型。到目前为止,你应该已经习惯了自己处理这个问题。
要点总结
下面是我们成功使用的方法的快速回顾:
领取专属 10元无门槛券
私享最新 技术干货