审校 | 胡永波

在现实生活中,文本信息无处不在。理解并学习文本数据的内在涵义一直是一个非常活跃的研究课题,这就是自然语言处理。

对于企业而言,利用文本数据可以对新产品的功能进行验证、改进并扩展。在这样的实际应用中,有三大类自然语言处理任务最为常见:

  • 识别不同的用户/客户群(如预测客户流失量、生命周期价值、产品偏好)
  • 准确地检测和提取不同类别的反馈信息(如正面和负面的评论/意见、衣服尺寸等特定属性的提及频率)
  • 根据用户的意图对文本信息进行分类(如请求基本帮助、紧急问题)
  • 尽管自然语言处理领域有很多在线的论文和教程资源,但很少有一些比较高效的指引和提示,以方便我们快速上手并解决这里的问题。这正是我们整理出本文的目的。

    在本文中,我们将分八大步骤来介绍如何用机器学习处理文本数据。我们将从最简单的方法开始,逐一讲解,然后分析更具体的方案细节,如特征工程、词向量和深度学习。你可以把本文看作是标准方法的高度概括。

    读完本文后,你将学会:

  • 如何收集,准备和检查数据
  • 如何建立简单的模型,有必要的话,应构建深度学习模型
  • 如何解释并理解你的模型,以确保模型学习的是特征信息而不是噪音
  • 此外,本文还附有一个交互式笔记,让你可以随意运行本文中的代码,来演示和应用其中的技术,特别是一些比较抽象的概念:

    代码链接 https://github.com/hundredblocks/concrete_NLP_tutorial/blob/master/NLP_notebook.ipynb

    步骤1:收集数据

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

  • 产品评论(在亚马逊、Yelp和各种应用商店)
  • 用户生成的内容(推文、Facebook帖子、StackOverflow问答)
  • 用户疑难解答(客户请求、客服支持记录、聊天记录)
  • “社交媒体灾难”数据集

    对于这篇文章,我们将使用一个由CrowdFlower所提供的“社交媒体灾难”的数据集 (链接:https://www.crowdflower.com/data-for-everyone/) ,其中:

    志愿者以“燃烧(ablaze)”、“隔离(quarantine)”、“混乱(pandemonium)”等作为关键词查找了超过1万条推文,并把推文内容是否跟灾难性事件(区分于这些词所指的笑话、电影评论或非灾难性话题)有关标记出来。

    由此,我们就可以判断哪些推文内容是在说灾难性事件,哪些是说像电影这样的不相关话题。为什么呢?因为存在一些情况,可能要让执法部门优先获知那些需要及时处理的紧急事件,而非关于Adam Sandler最新电影的海量评论。而这两类内容使用完全相同的关键词都能搜到,我们不得不使用更微妙的特征来区分它们,这是很大的挑战。

    本文接下来的内容,我们将含灾难性内容的推文称为“灾难性推文”,其他推文则被视为“不相关推文”。

    在样本数据中,每条推文属于哪个类别都已被标记出来。正如Richard Socher在推文中所说的,找到并标记足够的数据来训练有监督模型,往往是一条更快、更简单、成本更低的路径,远比难于优化的无监督方法有效。

    Richard Socher的观点

    步骤2:数据清洗

    机器学习的第一条原则是:“数据有多好,模型的性能才会有多好”。

    知道何时该调整模型何时要处理数据,这一能力是数据科学家的核心技能之一。一条良好的经验就是先查看数据进而把它清洗好。一个干净的数据集,可以让机器学习模型学到有意义的特征,而非过拟合在不想关的噪音信息上。

    下面列出了一些数据清洗的方法,你可以自己尝试 (更多细节见代码https://github.com/hundredblocks/concrete_NLP_tutorial/blob/master/NLP_notebook.ipynb)

  • 删除所有不相关的字符,如任何非字母或数字的字符串。
  • 将文本信息分离成单独的文字,并逐字进行标记。
  • 移除一些不相关的字词串,比如Twitter的“@”标识、网址链接等。
  • 将所有字幕转换为小写,避免重复识别“hello”,“Hello”和“HELLO”等同类词汇。
  • 考虑合并拼写错误或替代拼写的单词,如“cool”/“kewl”/“cooool”。
  • 考虑将不同变体的词形还原回来,如将“a”、“is”和“are”等单词还原成“be”的这种通用形式。
  • 按照上述步骤处理并检查数据后,我们就可以使用这些干净的标注数据来训练机器学习模型了!

    步骤3:找到一种好的数据表示

    机器学习模型通常以数值作为输入。例如,处理图像的模型是以每个颜色通道中像素值矩阵作为输入的。

    一副笑脸图可以被表示成这样的数字矩阵

    我们这里的数据集是句子列表,为了让模型可以从数据中学到句子的特征模式,我们首先要找到一种方法来把它转换成模型能理解的形式,即数字列表。

    独热编码(词袋)

    通常,计算机文本数据的表示是将每个字符编码成一个独特的数字(例如ASCII码表)。如果把这么简单的表示输入给分类器,它就只能根据这些数据从头来学习单词的结构,这对大部分数据集来说是不现实的。这就要求我们采用更高级的数据表示方法。

    例如,我们可以为数据集的所有词汇建立一个特定的词汇表,令每一个词汇对应一个唯一的索引值。这样,每句话均可表示为一个列表,列表的长度由词汇表中单词的数量来决定。列表的每处索引值,标识一个给定单词在句中出现的次数。这就是我们常说的词袋模型(bag-of-words),因为它完全无视单词在句中的先后次序。如下图所示:

    将句子表示为词袋模型(bag-of-words):左边是句子,右边是对应的表示。向量中的每个索引都代表一个特定的词。

    词嵌入模型的可视化

    在“社交媒体灾难”样本中,我们有大约20000个的单词,这意味着每个句子都会被表示成一个长度为20000的向量。该向量的大部分元素都是0,因为相对于完整的词汇表,每个句子都只是一个非常小的子集。

    为了进一步了解词嵌入模型能否捕获到与问题相关的信息(即推文内容是否与灾难有关),我们可以将其可视化并检查不同类别的数据是否能很好地分离。由于词汇表的量通常都非常大,在20000个维度上显示数据不现实,因此像PCA(主成分分析)这样能把数据降维到两个维度的技术就很有帮助了。绘图如下:

    词袋嵌入模型的可视化结果

    结果表明,这两类数据的分离效果不是很好。这可能是由于我们所嵌入的某一个特征,或仅仅是因为我所降低的特征维度。为了验证词袋模型(bag-of-words)所学到的特征是否对分类有用,我们可以用它们来训练一个分类器。

    步骤4:模型分类

    刚接触机器学习问题时,我们最好从能解决问题的最简单工具上手。每每涉及到数据的分类,Logistic回归都会是很好的选择。因为它的通用性与可解释性都很好,训练过程也非常简单,结果极易解释,很容易就能提取出模型中最重要的系数。

    我们将数据分成训练集和测试集,训练集用于生成模型,测试集用于检查模型在未知数据上的泛化情况。训练完成时,我们得出75.4%的分类准确度。还不算太差!而判断“不相关内容”时,准确度只有57%。尽管如此,75%的识别精度也足以满足我们的需求。下一步,在部署前,我们要做尽可能全面的可视化分析,并彻底理解这个模型。

    步骤5:模型检查

    理解模型的第一步是要知道模型错分的数据类型,以及最不应该出现的错误类别。在我们的例子中,假阳性结果是指将不相关推文错分为灾难性推文,而假阴性结果类则将灾难性推文归类为不相关推文。如果要优先处理潜在的灾难性事件,那我们要降低假阴性结果。而如果资源比较受限,我们就需要优先降低假阳性结果,以减少误报。使用混淆矩阵可以很好地可视化这里的信息,并将模型预测结果与数据的真实标签进行比较。理想情况下,混淆矩阵是一条从左上角到右下角的对角线(如果我们模型的预测结果能与真实标签完美匹配的话)。

    混淆矩阵(绿色部分所占比例较高,蓝色部分的比例较低)

    相比假阳性结果,我们的分类器产生了更多的假阴性结果。换句话说,模型中最常见的错误是将灾难性推文错误归类为不相关推文。如果假阳性结果的执法成本很高的话,那么我们分类器的这种偏差就是良性的。

    模型的可解释性

    为了验证模型并解释它的预测结果,我们需要明确模型用以进行判断的那些词汇。如果我们的数据有偏差,而分类器在样本数据中却能做出准确预测,那这样的模型就无法在现实世界中很好地推广。

    在这里,我们可以用图表来表示灾难性推文与不相关推文两类预测中最重要的词汇。由于我们可以对模型的预测系数进行提取和排序,用词袋模型(bag-of-words)和Logistic回归模型很容易就能计算出单词的重要性。

    词袋模型(bag-of-words):单词的重要性

    我们的分类器能够正确识别出一些模式(如广岛、大屠杀等),但在一些毫无意义的词汇(如heyoo、x1392等)上还是出现了过拟合。词袋模型(bag-of-words)仅能处理庞大词汇表内的不同词汇,并对所有的词汇分配相同的权重。然而,其中一些词汇出现得非常频繁,但却只是预测结果的噪音数据。接下来,我们将试着找到一种能够表示词汇在句子中出现频率的方法,尽量让模型从数据中获取更多的信号。

    步骤6:词汇结构的统计

    TF-IDF嵌入模型

    为了让模型专注于学习更有意义的词汇,我们可以在词袋模型上面使用TF-IDF评分(术语频率,逆文档频率)。TF-IDF通过词汇在数据集中的稀有程度来评估它的重要性,适度削弱出现过于频繁的单词。下图是TF-IDF嵌入模型的PCA映射:

    可视化TF-IDF嵌入模型

    从中可以看出,两种颜色之间有了更清晰的区分,使这两类数据更易于被分类器分开。在新模型上训练Logistic回归,我们得到了76.2%的准确度,说明TF-IDF确实有助于提高识别性能。

    尽管只是非常微小的改进,但我们的模型能否就此学到更重要的词汇呢?如果能得到更好的结果,同时还能避免模型在无关词汇上的过拟合,那TF-IDF嵌入模型就可以被认为是真正的“升级版”模型。

    TF-IDF嵌入模型:单词的重要性

    可以看到,新模型学到的词汇看起来相关度更高!尽管测试集的指标只是略有增加,但是我们对模型的识别性能更有把握,因此部署新模型的交互系统会让用户体验更为舒适。

    步骤7:语义信息的利用

    Word2Vec

    TF-IDF嵌入模型能够学习到信号更高频的词汇。然而,如果部署该模型后,我们很可能会遇到一些训练集中从未出现过的词汇。先前的模型均无法正确分类这样的新数据,即便其中的词汇与训练集非常相似。

    要解决这个问题,我们就要捕捉词汇的语义,这就意味着模型需要理解“好”与“积极”在语义上的距离要比“杏”和“大陆”更接近。这里的工具就是Word2Vec。

    使用预训练的嵌入模型

    Word2Vec是一种为单词查找连续嵌入的技术。通过阅读大量的文字,它能够学习并记忆那些倾向于在相似语境中出现的词汇。经过足够的数据训练之后,它会为词汇表中的每个单词都生成一个300维的向量,用以记录语义相近的词汇。

    Word2Vec作者在一个非常大的语料库上预训练并开源了该模型。利用这一语料库,我们可以将一些语义知识纳入到我们的模型内。预训练好的词向量可以在本文的GitHub代码库中找到。

    GitHub地址:

    https://github.com/hundredblocks/concrete_NLP_tutorial

    句子分级表示

    让分类器快速得到句子嵌入的方法,是先将句中所有词汇Word2Vec得分的平均化。这与此前词袋模型的做法类似,但这里我们在保留语义信息的同时只丢弃句法。

    Word2vec模型的句子嵌入

    利用前面的可视化技术对新模型绘图,结果如下:

    Word2Vc嵌入模型的可视化结果

    在这里,两组颜色的分离程度更大一些,这就意味着Word2Vec能够帮助分类器更好地分离这两种类别。再一次使用Logistic回归,得到77.7%的准确率,是我们迄今最好的结果!

    复杂性/可解释性权衡取舍

    与先前的模型不同,新模型无法将每个单词都表示成一维向量,因此很难看出哪些词汇与我们的分类结果相关度最高。尽管我们仍可使用Logistic回归的系数,但它们仅与嵌入的300个维度相关,而与词汇索引值并不相关。

    模型准确率确实提高了,但完全做不了可解释性分析就有点得不偿失了。不过,对于更复杂的模型,我们可以利用LIME这样的“黑盒解释器”来稍微解释一下分类器具体是如何工作的。

    LIME是Github上的一个开源软件包,它允许用户通过观察输入的扰动(比如在我们的例子中,从句中移除单词)来分析一个特定分类器的预测结果是如何变化的。

    从下图来看它对我们数据集中几个句子的解释:

    正确分类的灾难性词汇被归类为“相关”

    这个词对分类的影响似乎不太明显

    不过,我们没有时间去逐一探索数据集中的数千个样本。我们要做的是在代表性的测试样本上运行LIME,以此来分析哪些词汇对于分类预测的影响更大。这样,我们就可以像前面一样获取到单词的重要性分数,以验证模型的预测结果。

    Word2Vec:单词的重要性

    模型能够提取高度相关的词,这意味着它做出了可解释的决定。这些词汇的相关度是最高的,因此我们更愿意在实际生产中部署这样的模型。

    步骤8:使用端到端的方式训练语法特征

    我们已经介绍过如何用快速有效的办法来生成紧凑的句子嵌入。然而,通过省略词汇的顺序,我们也放弃了语句的所有句法信息。如果简单的方法给不出令人满意的结果,那我们就用更为复杂的模型:将整个句子作为输入并预测标签,同时无需建立中间表示。一种常见的做法是把句子视为词向量的序列,如使用Word2Vec,或是GloVe、CoVe等更先进的方法。接下来我们详细讨论。

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

    用于句子分类的卷积神经网络 https://arxiv.org/abs/1408.5882 训练速度很快快。它作为一种入门级的深度学习架构,能够很好地解决分类问题。尽管CNN声名主要源自它在图像处理方面的出色能力,但在文本相关任务上,它所提供的结果也相当优异。且相比多数复杂的NLP方法(如LSTM、Encoder/Decoder架构等),CNN训练速度也更快。它能够保留单词的顺序,很好地学习单词的序列特征以及其他有用信息。相对于先前的模型,它可以区分出“Alex eats plants”与“Plants eat Alex”之间差异。

    相比先前的方法,该模型的训练不需更多的工作,但效果却好得多,准确率高达79.5%!与前面的步骤一样,下一步也要继续探索并可视化该模型的预测结果,以验证它是否为最佳模型。做到这一步,你应该能自己完成这里的操作。

    简单回顾一下,我们在各个步骤中所用的方法是这样的:

  • 从一个简单的模型快速开始
  • 解释模型的预测
  • 理解模型分类中的错误样本
  • 使用这些知识来决定下一步的部署。
  • 上述八大步骤所用的模型是我们处理短文本时的几个特定实例,但其背后的解决方法已经广泛被用在各类NLP问题的实际处理上。

    原文链接:

    https://blog.insightdatascience.com/how-to-solve-90-of-nlp-problems-a-step-by-step-guide-fda605278e4e 返回搜狐,查看更多

    责任编辑:

    声明:该文观点仅代表作者本人,搜狐号系信息发布平台,搜狐仅提供信息存储空间服务。