原文:
annas-archive.org/md5/836603e6421cae6c5dff3191c58dc5a0
译者:飞龙
前言
自然语言理解(NLU)是一种将语言结构化的技术,使计算机系统能够进一步处理语言,从而执行有用的应用程序。
开发人员将发现,本实用指南能够帮助他们利用 NLU 技术开发多种类型的 NLU 应用;而管理者将能够识别出可以应用 NLU 来解决实际问题的领域。
本书提供了逐步解释的基本概念和实际示例,你将首先学习 NLU 是什么及其如何应用。然后,你将了解当前广泛的 NLU 技术,以及了解每种技术最佳应用场景,包括新的大型语言模型(LLMs)。在此过程中,你将接触到最有用的 Python NLU 库。你不仅会学习 NLU 的基础知识,还会了解许多实际问题,例如数据获取、系统评估、提升系统效果以及部署 NLU 应用。最重要的是,你不仅会学到一系列技术,还会学会如何在未来的工作中利用网络上丰富的 NLU 资源。
本书适合谁阅读
对于有兴趣了解 NLU 并将自然语言处理(NLP)技术应用于实际问题的 Python 开发人员,本书将带来最大收益,包括计算语言学家、语言学家、数据科学家、NLP 开发人员、对话 AI 开发人员以及这些领域的学生。前几章也将对非技术项目经理具有吸引力。
本书的最佳使用效果要求具备一定的 Python 基础。你无需具备任何自然语言理解(NLU)的先前知识。
本书内容简介
本书包括十五章内容,将引导你完成一个从理解 NLU 是什么,选择应用、开发系统,到如何改进你已开发的系统的过程。
第一章,自然语言理解、相关技术与自然语言应用,提供了关于 NLU 是什么的解释,并说明它与语音识别等相关技术的区别。
第二章,识别实际的自然语言理解问题,系统地讲解了 NLU 的多种潜在应用,并回顾了每种应用类型的具体需求。它还审视了应用中可能使得当前技术难以实现的方面。
第三章,自然语言理解方法——基于规则的系统、机器学习与深度学习,概述了自然语言理解(NLU)的主要方法,并讨论了它们的优缺点,包括基于规则的技术、统计技术和深度学习。它还讨论了流行的预训练模型,如 BERT 及其变体。最后,它讨论了将不同方法结合起来形成解决方案。
第四章,为自然语言理解选择库和工具,帮助你为处理自然语言做好准备。首先讨论了一些通用工具,如 Jupyter Labs 和 GitHub,以及如何安装和使用它们。接着讨论了安装 Python 以及用于 NLU 的多种 Python 库。讨论的库包括 NLTK、spaCy 和 TensorFlow/Keras。
第五章,自然语言数据——查找与准备数据,教你如何识别并准备数据以便使用 NLU 技术进行处理。它讨论了来自数据库、网络和其他文档的数据,以及隐私和伦理问题。简要介绍了“奥兹巫师”技术及其他模拟数据采集方法,如数据生成。对于没有自己数据的用户,或那些希望将自己的结果与其他研究人员的结果进行比较的用户,本章还讨论了常用的、广泛可用的语料库。然后,它进一步讨论了预处理步骤,如词干提取和词形还原。
第六章,探索与可视化数据,讨论了获取数据整体概貌的探索性技术,例如汇总统计(词频、类别频率等)。还将讨论可视化工具,如 matplotlib。最后,它讨论了基于可视化和统计结果可以做出的决策类型。
第七章,选择方法与表示数据,讨论了选择方法时需要考虑的因素,例如数据量、训练资源和预期应用。 本章还讨论了如何使用向量和嵌入等技术表示语言,为定量处理做好准备。它还讨论了通过使用管道来结合多种方法。
第八章,基于规则的技术,讨论了如何将基于规则的技术应用于具体的应用场景。示例包括正则表达式、词形还原、句法分析、语义角色分配和本体论。本章主要使用 NLTK 库。
第九章,机器学习第一部分 - 统计机器学习,讨论了如何将统计机器学习技术如朴素贝叶斯、TF-IDF、支持向量机和条件随机场应用于分类、意图识别和实体提取等任务。重点将放在如 SVM 等新技术上,并探讨它们如何比传统方法提供更好的性能。
第十章,机器学习第二部分 – 神经网络与深度学习技术,介绍了基于神经网络(全连接网络、CNN 和 RNN)的机器学习技术在分类和信息提取等问题中的应用。本章将使用这些方法的结果与前一章中描述的方法进行比较。章节讨论了神经网络的概念,如超参数、学习率和训练迭代。本章使用了 TensorFlow/Keras 库。
第十一章,机器学习第三部分 – Transformer 和大型语言模型,涵盖了当前在自然语言处理领域表现最佳的技术——Transformer 和预训练模型。它讨论了 Transformer 背后的原理,并提供了一个使用 Transformer 进行文本分类的示例。本章的代码基于 TensorFlow/Keras Python 库。
第十二章,应用无监督学习方法,讨论了无监督学习的应用,如主题建模,包括无监督学习在探索性应用和最大化稀缺数据中的价值。本章还涉及了弱监督和远程监督等部分监督类型。
第十三章,它的效果如何?——评估,涉及定量评估。包括将数据分割为训练集、验证集和测试集,使用交叉验证进行评估,以及精度、召回率、曲线下面积、消融研究、统计显著性和用户测试等评估指标。
第十四章,如果系统无法正常工作该怎么办,讨论了系统维护。如果原始模型不足以满足需求,或者现实世界中的情况发生了变化,模型应该如何调整?本章讨论了如何添加新数据并更改应用结构,同时确保新数据不会降低现有系统的性能。
第十五章,总结与展望,提供了本书的概述,并展望了未来。讨论了在性能改进的潜力所在,以及更快的训练、更具挑战性的应用、未来的技术方向和这个激动人心的技术研究领域的前景。
为了最大限度地利用本书
本书的代码以 Jupyter Notebooks 的形式提供。为了运行这些笔记本,你应该对 Python 编程有一定了解,并且熟悉一些基本的库。此外,你还需要安装所需的包。
安装它们的最简单方法是使用 Pip,这是一个很棒的 Python 包管理工具。如果系统中尚未安装 Pip,你可以在这里找到安装说明:pypi.org/project/pip/
。
对 Python 编程语言的工作知识将有助于理解本书中涉及的关键概念。本书中的示例不需要 GPU,可以在 CPU 上运行,尽管一些更复杂的机器学习示例在配备 GPU 的计算机上运行会更快。
本书的代码仅在 *Windows 11(64 位)*上进行过测试。
书中使用的 软件/硬件 | 操作系统 要求 |
---|---|
基本平台工具 | |
Python 3.9 | Windows、macOS 或 Linux |
Jupyter Notebooks | |
pip | |
自然语言处理与机器学习 | |
NLTK | Windows、macOS 或 Linux |
spaCy 和 displaCy | |
Keras | |
TensorFlow | |
Scikit-learn | |
图形绘制与可视化 | |
Matplotlib | Windows、macOS 或 Linux |
Seaborn |
下载示例代码文件
你可以在 GitHub 上下载本书的示例代码文件:github.com/PacktPublishing/Natural-Language-Understanding-with-Python
。如果代码有更新,它将在 GitHub 仓库中更新。
我们还提供了来自我们丰富书籍和视频目录中的其他代码包,您可以在github.com/PacktPublishing/
找到它们。快来看看吧!
下载彩色图片
我们还提供了一份包含本书中截图和图表的彩色图片的 PDF 文件。你可以在这里下载:packt.link/HrkNr
。
使用的约定
本书中使用了许多文本约定。
文本中的代码
:表示文本中的代码词、数据库表名、文件夹名称、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 用户名。例如:“我们将使用 ENCOAdjacencyDistributionModule
对象来建模邻接矩阵。”
代码块的格式如下:
preds = causal_bert.inference(
texts=df['text'],
confounds=df['has_photo'],
)[0]
所有命令行输入或输出如下所示:
$ pip install demoji
粗体:表示新术语、重要单词或屏幕上显示的单词。例如,菜单或对话框中的单词显示为粗体。例如:“从管理面板中选择系统信息。”
提示或重要说明
以这种形式显示。
联系我们
我们总是欢迎读者的反馈。
一般反馈:如果你对本书的任何部分有疑问,请通过电子邮件与我们联系,邮件主题中注明书名:customercare@packtpub.com。
勘误表:虽然我们已经尽最大努力确保内容的准确性,但错误仍然可能发生。如果你在本书中发现任何错误,请帮助我们报告。请访问 www.packtpub.com/support/errata 并填写表格。
盗版:如果你在互联网上发现任何形式的非法复制品,恳请你提供相关的地址或网站名称。请通过电子邮件联系 copyright@packt.com 并附上相关链接。
如果你有兴趣成为作者:如果你在某个领域有专业知识,并且有兴趣写书或参与书籍的编写,请访问 authors.packtpub.com。
分享你的想法
一旦你读完*《Python 与自然语言理解》*,我们非常希望听到你的想法!请点击这里直接访问本书的 Amazon 评论页面并分享你的反馈。
你的评价对我们和技术社区非常重要,将帮助我们确保提供卓越的内容质量。
下载本书的免费 PDF 版本
感谢你购买本书!
你喜欢在路上阅读,但又无法随身携带纸质书籍吗?
你的电子书购买是否与你选择的设备不兼容?
不用担心,现在每本 Packt 书籍都可以获得免费的无 DRM 保护的 PDF 版本。
在任何地方、任何时间,任何设备上阅读。直接将你最喜爱的技术书中的代码搜索、复制并粘贴到你的应用程序中。
福利不仅于此,你还可以获得独家折扣、新闻简报以及每天在收件箱中收到精彩的免费内容。
按照以下简单步骤获取福利:
- 扫描二维码或访问以下链接
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_QR_Free_PDF.jpg
packt.link/free-ebook/9781804613429
-
提交购买证明
-
就这样!我们将直接把你的免费 PDF 和其他福利发送到你的电子邮件。
第一部分:自然语言理解技术入门
在第一部分中,你将了解自然语言理解及其应用。你还将学习如何判断自然语言理解是否适用于特定问题。此外,你还将了解不同自然语言理解技术的相对成本与收益。
本部分包含以下章节:
-
第一章,自然语言理解、相关技术与自然语言应用
-
第二章,识别实际的自然语言理解问题
第一章:自然语言理解、相关技术和自然语言应用
自然语言,无论是口语还是书面语言,都是我们与他人沟通的方式。使用自然语言与他人交流的能力是使我们成为社区完整成员的重要部分。年轻孩子的第一句话是全球范围内的庆祝事件。理解自然语言通常看起来毫不费力,除非出了什么问题。当我们在使用语言时遇到困难,无论是因为疾病、受伤,还是处在外国,它都让我们深刻意识到语言在我们生活中的重要性。
在本章中,我们将描述自然语言及其处理所能获得的有用结果。我们还将把自然语言处理(NLP)置于相关对话式 AI 技术的生态系统中。我们将讨论自然语言出现的地方(文档、语音、数据库中的自由文本字段等),谈论特定的自然语言(英语、中文、西班牙语等),并介绍 NLP 的技术,介绍用于 NLP 的 Python。
本章将涵盖以下主题:
-
理解自然语言的基础
-
全球考虑因素
-
对话式 AI 与自然语言处理(NLP)之间的关系
-
探索互动应用
-
探索非互动应用
-
展望未来 – Python 在 NLP 中的应用
学习这些主题将帮助你对 NLP 领域有一个总体的了解。你将学习它的应用场景,它与其他对话式 AI 主题的关系,以及它能解决的各种问题。你还将了解到 NLP 应用对最终用户和组织的众多潜在好处。
阅读完本章后,你将能够识别适用于你感兴趣问题的 NLP 技术领域。无论你是企业家、组织开发者、学生,还是研究人员,都能将 NLP 应用于你的具体需求。
理解自然语言的基础
我们尚未拥有能够提取人类理解自然语言时所体验的丰富意义的技术;然而,在特定的目标和应用下,我们会发现目前的技术水平可以通过 NLP 帮助我们实现许多实用、有益且具有社会效益的结果。
口语和书面语言无处不在,丰富多彩。口语出现在人们与智能系统之间的日常对话中,也出现在广播、电影和播客等媒体中。书面语言则出现在网页上、书籍中以及人们之间的通信中,例如电子邮件。书面语言还出现在表单和数据库的自由文本字段中,这些文本可能在线上可用,但未被搜索引擎索引(隐形网络)。
所有这些语言形式,在分析时,都可以成为无数类型应用的基础。本书将奠定基本的分析技术基础,帮助你在许多不同的应用中利用自然语言。
全球化考虑因素 – 语言、编码和翻译
世界上有成千上万种自然语言,包括口语和书面语言,尽管根据Babbel.com的资料(www.babbel.com/en/magazine/the-10-most-spoken-languages-in-the-world
),世界上大多数人说的是排名前十的语言。在本书中,我们将重点关注主要的世界语言,但必须注意,不同的语言可能会为自然语言处理(NLP)应用带来不同的挑战。例如,书面汉语不在单词之间添加空格,而大多数 NLP 工具依赖空格来识别文本中的单词。这意味着,在处理汉语时,除了识别空格之外,还需要额外的步骤来分隔汉字。这在以下由 Google 翻译的示例中得到了体现,其中汉字之间没有空格:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_01_01.jpg
图 1.1 – 书面汉语不通过空格来分隔单词,与大多数西方语言不同
另一个需要注意的考虑因素是,一些语言中的同一个词会有许多不同的形式,这些形式通过不同的词尾提供关于其特定属性的信息,例如词在句子中所扮演的角色。如果你主要说英语,可能习惯了很少有词尾变化的词汇。这使得应用程序相对容易检测到同一个词的多次出现。然而,这并不适用于所有语言。
例如,在英语中,词汇walked可以在不同的语境中使用,保持相同的形式但含义不同,比如I walked(我走了),they walked(他们走了),或者she has walked(她已经走了);而在西班牙语中,同一个动词(caminar)则有不同的形式,如Yo caminé(我走了),ellos caminaron(他们走了),或者ella ha caminado(她已经走了)。这对 NLP 的影响是,可能需要额外的预处理步骤,才能成功分析这些语言中的文本。我们将在第五章讨论如何为需要这些步骤的语言添加预处理步骤。
另一个需要记住的事情是,不同语言的处理工具的可用性和质量差异很大。对于主要的世界语言,如西欧语言和东亚语言,通常有相对较好的工具可用。然而,讲者少于 1000 万的语言可能没有任何工具,或者现有的工具可能不太好。这是由于训练数据的可用性以及商业利益较少等因素造成的。
资源相对较少的语言被称为低资源语言。对于这些语言,缺乏足够的书面语言示例来以标准方式训练大型机器学习模型。此外,能够提供语言工作原理见解的讲者也很少。这些语言可能是濒危语言,或者仅由少数人群使用。针对这些语言开发自然语言技术的技术正在积极研究中,尽管对于某些语言,开发自然语言技术可能不可行,或代价过高。
最后,许多广泛使用的语言并不使用罗马字母,例如中文、俄语、阿拉伯语、泰语、希腊语和印地语等。处理使用非罗马字母的语言时,重要的是要认识到工具必须能够接受不同的字符编码。字符编码用于表示不同书写系统中的字符。在许多情况下,文本处理库中的函数有参数,允许开发者指定他们打算处理的文本所需的编码。在选择适用于使用非罗马字母的语言的工具时,必须考虑处理所需编码的能力。
对话式 AI 与 NLP 之间的关系
对话式人工智能是一个广泛的术语,用于指代一系列协作技术,旨在使系统能够与人进行语音和基于文本的对话。这些技术包括语音识别、NLP、对话管理、自然语言生成和语音合成。区分这些技术非常重要,因为它们常常被混淆。尽管本书将重点关注 NLP,但我们将简要定义其他相关技术,以便了解它们如何协同工作:
-
语音识别:这也被称为语音转文本或自动语音识别(ASR)。语音识别技术从语音音频开始,并将其转换为文本。
-
NLP:这一技术从书面语言开始,生成可以被计算机处理的结构化表示。输入的书面语言可以是语音识别的结果,也可以是原本以书面形式生成的文本。结构化格式可以被认为表达了用户的意图或目的。
-
对话管理:这始于自然语言处理的结构化输出,并决定系统应如何反应。系统的反应可以包括提供信息、播放媒体或获取更多用户信息,以满足其意图。
-
自然语言生成:这是创建文本信息的过程,用于表达对话管理器对用户发言的反馈。
-
文本转语音:基于自然语言生成过程创建的文本输入,文本转语音组件在给定文本时生成语音输出。
这些组件之间的关系如下图所示,展示了一个完整的语音对话系统。本书重点讨论自然语言处理组件。然而,由于许多自然语言应用会使用其他组件,如语音识别、文本转语音、自然语言生成和对话管理,因此我们偶尔也会提到它们:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_01_02.jpg
图 1.2 – 完整的语音对话系统
在接下来的两个部分,我们将总结一些重要的自然语言应用。这将让你了解本书将涉及的技术的潜力,并希望能激发你对使用广泛可用工具所能实现的成果的兴趣。
探索互动应用——聊天机器人和语音助手
我们可以将自然语言处理应用大致分为两类,即互动应用,其分析的基本单元通常是对话;以及非互动应用,其分析的单元通常是文档或一组文档。
互动应用包括用户与系统实时对话或文本交流的应用。熟悉的互动应用包括聊天机器人和语音助手,如智能音响和客户服务应用。由于其互动性,这些应用要求系统提供非常快速、几乎是即时的响应,因为用户在等待系统的回应。用户通常不能容忍超过几秒钟的延迟,因为这是他们与他人交谈时所习惯的。另一个特点是这些应用的用户输入通常非常简短,在语音互动的情况下,通常只有几个词或几秒钟长。这意味着依赖于大量文本进行分析的技术在这些应用中并不适用。
互动应用的实现很可能需要前述系统图中的其他一个或多个组件,除了自然语言处理(NLP)本身。显然,具有语音输入的应用需要语音识别,而以语音或文本回应用户的应用则需要自然语言生成和语音合成(如果系统的响应是语音)。任何超出回答单一问题的应用也需要某种形式的对话管理,以便跟踪用户在先前话语中所说的内容,在解释后续话语时考虑这些信息。
意图识别是互动自然语言应用中的一个重要方面,我们将在第九章和第十四章中详细讨论。意图本质上是用户发出话语时的目标或目的。显然,了解用户的意图对于提供正确信息至关重要。除了意图,互动应用通常还需要识别用户输入中的实体,实体是系统需要的附加信息,以便满足用户的意图。例如,如果用户说:“我想从波士顿预定一班飞往费城的航班”,意图是进行航班预订,相关实体是出发地和目的地城市。由于预订航班还需要旅行日期,因此这些也是实体。由于用户在此话语中未提及旅行日期,系统应该询问用户日期,这是一个称为槽位填充的过程,将在第八章中讨论。实体、意图和话语之间的关系可以在图 1.3中看到:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_01_03.jpg
图 1.3 – 旅行规划话语的意图和实体
请注意,意图适用于话语的整体含义,而实体则仅代表话语中具体部分的含义。这一区别很重要,因为它影响了用于处理这些话语的机器学习技术的选择。第九章将更详细地讨论这一主题。
通用语音助手
通过智能音响或手机访问的通用语音助手,如亚马逊 Alexa、苹果 Siri 和谷歌助手,大多数人都很熟悉。通用助手能够为用户提供一般性的信息,包括体育比分、新闻、天气以及有关知名公众人物的信息。它们还可以播放音乐并控制家庭环境。与这些功能相对应,通用助手识别的意图类型包括获取的天气预报,其中*代表一个有助于完成获取天气预报意图的实体。类似地,“比赛的比分是多少?”具有获取比赛比分*的意图,特定团队的名称是该意图的实体。这些应用程序具有广泛但通常较为浅显的知识。在大多数情况下,它们与用户的互动仅基于一个或最多几个相关的输入——也就是说,它们大多数情况下无法进行长时间的对话。
通用语音助手主要是封闭和专有的。这意味着开发者几乎没有机会向助手添加通用功能,例如添加新的语言。然而,除了前面提到的专有助手外,还有一个名为Mycroft的开源助手,它允许开发者向底层系统添加功能,而不仅仅是使用平台提供的工具。
企业助手
与通用语音助手不同,一些交互式应用程序具有关于特定公司或其他组织的深度信息。这些被称为企业助手。它们旨在执行与公司相关的特定任务,如客户服务,或提供有关政府或教育组织的信息。它们可以执行的操作包括检查订单状态、为银行客户提供账户信息,或让公用事业客户了解停电情况。它们通常连接到大量的客户或产品信息数据库;因此,基于这些信息,它们可以提供深度但主要是狭窄的专业领域知识。例如,它们可以告诉你某个公司产品是否有库存,但它们不知道你最喜欢的体育队最新比赛的结果,而通用助手在这方面做得非常好。
企业语音助手通常使用如 Alexa 技能包、Microsoft LUIS、Google Dialogflow 或 Nuance Mix 等工具包开发,尽管也有像 RASA 这样的开源工具包(rasa.com/
)。这些工具包非常强大且易于使用。它们只需要开发者提供工具包需要在用户话语中找到的意图和实体的示例,以便理解他们想要做什么。
类似地,基于文本的聊天机器人可以执行与语音助手相同的任务,但它们通过文本而非语音的形式从用户那里获取信息。聊天机器人在网站上变得越来越普遍。它们可以提供网站上可用的大部分信息,但由于用户可以直接表明自己感兴趣的内容,它们避免了用户必须在可能非常复杂的网站中进行搜索。用于语音助手的工具包在许多情况下也可以用来开发基于文本的聊天机器人。
在本书中,我们不会花太多时间讨论商业工具包,因为创建可用应用所需的编码非常少。相反,我们将重点介绍支撑商业工具包的技术,这将使开发人员能够在不依赖商业系统的情况下实现应用。
翻译
交互式应用的第三大类是翻译。与前面描述的助手不同,翻译应用用于帮助用户与其他人进行沟通——即,用户不是在与助手对话,而是在与另一个人对话。实际上,这些应用充当了翻译员的角色。该应用在两种不同的人类语言之间进行翻译,以使两位不讲共同语言的人能够相互交流。这些应用可以基于语音或输入的文本。尽管语音输入更快且更自然,但如果发生语音识别错误(这是常见的情况),则可能会显著干扰两人之间沟通的流畅性。
当对话内容较为简单,例如旅游信息时,交互式翻译应用最为实用。对于更复杂的话题——例如商务谈判——成功的可能性较低,因为其复杂性导致了更多的语音识别和翻译错误。
教育
最后,教育是交互式自然语言处理(NLP)的一个重要应用。语言学习可能是最自然的教育应用。例如,有些应用帮助学生与他们正在学习的新语言进行对话。这些应用相较于与其他人练习对话具有优势,因为应用不会感到无聊,且它们是持续一致的,用户在犯错时也不会感到尴尬。其他教育应用包括帮助学生学习阅读、学习语法,或者在任何学科上进行辅导。
图 1.4 是不同种类交互式应用及其关系的图示总结:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_01_04.jpg
图 1.4 – 交互式应用的层级
到目前为止,我们已经讨论了交互式应用,其中终端用户与 NLP 系统直接进行实时对话或输入文字。这些应用的特点是用户输入短小,需要快速响应。现在,我们将转向非交互式应用,在这些应用中,语音或文本在没有用户在场的情况下进行分析。要分析的材料可以是任意长的,但处理时间不必是即时的。
探索非交互式应用程序
另一种主要的自然语言应用类型是非交互式应用,或称离线应用。这些应用中的主要工作由 NLP 组件完成。系统图中的其他组件通常不需要。这些应用是在现有文本上执行的,不需要用户在场。这意味着实时处理不是必需的,因为用户不在等待答案。同样,系统也不需要等待用户决定说什么,因此,在许多情况下,处理可以比交互式应用更快速地进行。
分类
一类非常重要且广泛应用的非交互式自然语言应用是文档分类,即根据文档内容将其分配到不同的类别。分类一直是自然语言处理(NLP)中的一个重要应用领域,并且已经采用了多种方法来解决。
分类的一个简单例子是一个网页应用程序,通过将查询分类到给定类别之一来回答客户的常见问题(FAQs),然后提供每个类别的预先准备好的答案。对于这种应用程序,分类系统比仅允许客户从列表中选择问题更为合适,因为分类系统可以自动将问题分类到数百个 FAQ 类别中,节省了客户必须浏览一个庞大的类别列表的时间。另一个有趣的分类问题是自动为电影分配类别——例如,根据评论或情节摘要来进行分类。
情感分析
concern
、break
、problem
、issues
、send back
和 hurt my back
),这段评论实际上是积极的:
“我曾担心这张椅子虽然很舒适,但由于椅腿很细,可能在我使用不久后就会坏掉。结果这并没有成为问题。我曾想着可能需要退货。到目前为止我没有遇到任何问题,它是我拥有的唯一一把不会伤害 我背部的椅子。”
需要更复杂的自然语言处理(NLP)技术,考虑上下文才能识别这是一条正面评价。情感分析是一个非常有价值的应用,因为如果有成千上万条现有的产品评价,并且新的产品评价不断加入,企业很难手动完成此任务。公司不仅希望了解他们的产品如何被客户看待,而且了解竞争产品的评价与自己产品的评价相比如何,也是非常宝贵的。如果有几十种类似的产品,相关评价的数量将大大增加。文本分类应用可以自动化很多这个过程。这是学术 NLP 领域一个非常活跃的研究方向。
垃圾邮件和网络钓鱼检测
垃圾邮件检测是另一个非常有用的分类应用,其目标是将电子邮件消息分为用户希望查看的消息和应被丢弃的垃圾邮件。这个应用不仅非常实用,而且具有挑战性,因为垃圾邮件发送者不断尝试绕过垃圾邮件检测算法。这意味着垃圾邮件检测技术必须与创建垃圾邮件的新方式同步发展。例如,垃圾邮件发送者经常故意拼写错误那些通常会被用来标示垃圾邮件的关键词,例如将数字1替换字母l,或将数字0替换字母o。虽然人类很容易理解这样拼写错误的单词,但计算机寻找的关键词将不再匹配,因此垃圾邮件检测技术必须被开发出来,以发现这些技巧。
与垃圾邮件检测密切相关的是检测那些试图通过网络钓鱼欺骗用户,或诱使他们点击链接或打开文档,从而使恶意软件被加载到其系统中的消息。在大多数情况下,垃圾邮件仅仅是一个烦恼,但网络钓鱼则更加严重,因为如果用户点击了网络钓鱼链接,可能会带来极具破坏性的后果。因此,任何能提高网络钓鱼消息检测的技术都会非常有益。
假新闻检测
另一个非常重要的分类应用是假新闻检测。假新闻是指看起来非常像真实新闻,但包含不真实的信息,旨在误导读者。像垃圾邮件检测和网络钓鱼检测一样,假新闻检测也充满挑战,因为制造假新闻的人会积极避免被检测到。检测假新闻不仅对于保护用户安全很重要,而且从平台角度来看也很重要,因为如果平台不断发布假新闻,用户将开始不信任这些平台。
文档检索
文档检索是找到解决用户搜索查询的文档的任务。最好的例子就是我们每天进行的常规网页搜索。网页搜索是文档检索的最著名例子,但文档检索技术也用于在任何文档集合中寻找信息——例如,在数据库或表单的自由文本字段中。
文档检索是基于找到用户查询与存储文档之间的良好匹配,因此需要分析用户的查询和文档。文档检索可以通过关键词搜索来实现,但简单的关键词搜索容易出现两种错误。首先,查询中的关键词可能与文档中的匹配关键词有不同的含义。例如,如果用户正在寻找一副新的眼镜,想到的是眼镜,他们不想看到饮用杯的结果。另一种错误类型是由于关键词不匹配,导致找不到相关结果。如果用户只使用了关键词眼镜,而使用眼镜或眼镜配件等关键词可能找到的结果却被遗漏,即使用户对这些信息感兴趣。使用 NLP 技术代替简单的关键词搜索可以帮助提供更精确的结果。
分析
另一个重要且广泛的自然语言应用领域是分析。分析是一个总括性术语,用于描述那些试图从文本中获取见解的 NLP 应用程序,这些文本通常是从口语交互转录出来的。一个好的例子是查看客户与呼叫中心代理之间的互动转录,以发现代理是否因客户的提问而感到困惑或提供了错误的信息。分析结果可以用于呼叫中心代理的培训。分析还可以用于检查社交媒体帖子,以找出当前的热门话题。
信息提取
信息提取是一种应用类型,其中结构化信息(如可用于填充数据库的信息)从文本中提取出来,例如从报纸文章中提取的信息。关于事件的重要信息,如日期、时间、参与者和地点,可以从报道新闻的文本中提取出来。这些信息与我们之前讨论的聊天机器人和语音助手中的意图和实体非常相似,我们会发现许多相同的处理技术对于这两种应用都很相关。
信息提取应用中的一个额外问题是命名实体识别(NER),它用于识别指代真实人物、组织和地点的内容。在像报纸文章这样的扩展文本中,通常会有多种方式来指代同一个人。例如,乔·拜登可能会被称为总统、拜登先生、他,甚至是前副总统。在识别乔·拜登的指代时,信息提取应用还必须避免将拜登博士的指代误解为乔·拜登的指代,因为那实际上指的是他的妻子。
翻译
翻译,也称为机器翻译,自 NLP 领域开始以来,一直是最重要的应用之一。机器翻译尚未完全解决,但在过去几年中已经取得了巨大进展。像 Google 翻译和 Bing 翻译这样的常见 Web 应用程序通常在网页等文本的翻译上做得非常好,尽管仍然有改进的空间。
像 Google 和 Bing 这样的机器翻译应用在翻译其他类型文本时效果较差,例如包含大量专业词汇的技术文本或朋友之间可能使用的口语化文本。根据维基百科(en.wikipedia.org/wiki/Google_Translate
),Google 翻译可以翻译 109 种语言。然而,应该记住的是,较少使用的语言的翻译准确度低于更常用语言的准确度,正如在全球 考虑因素部分所讨论的那样。
摘要、写作、语法纠正和其他应用
就像人类有很多理由阅读和理解文本一样,能够读取和理解文本的系统也有许多应用场景可以发挥作用。检测抄袭、纠正语法、评分学生作文以及确定文本的作者身份只是其中的一些应用。总结长文本也非常有用,简化复杂文本也是如此。当原始输入是非交互式语音时,比如播客、YouTube 视频或广播,文本的总结和简化同样可以应用。
图 1.5 是对非交互式应用讨论的图形总结:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_01_05.jpg
图 1.5 – 非交互式应用的层级结构
图 1.5 显示了我们所讨论的非交互式 NLP 应用程序之间的关系。很明显,分类是一个主要的应用领域,我们将在第九章、第十章和第十一章中深入探讨它。
应用类型的总结
在前面的章节中,我们看到不同类型的交互式和非交互式应用是如何相互关联的。显然,NLP 可以应用于解决许多不同且重要的问题。在本书的其余部分,我们将深入探讨适用于解决不同类型问题的具体技术,你将学会如何为每个问题选择最有效的技术。
展望未来——Python 在 NLP 中的应用
传统上,NLP 是通过多种计算机语言来实现的,从早期的专用语言,如 Lisp 和 Prolog,到更现代的语言,如 Java 和如今的 Python。目前,Python 可能是 NLP 最受欢迎的语言,部分原因是有趣的应用可以相对快速地实现,开发人员可以迅速获得他们想法的反馈结果。
Python 的另一个主要优势是有大量有用、经过充分测试且文档完备的 Python 库可以应用于 NLP 问题。这些库包括 NLTK、spaCy、scikit-learn 和 Keras,仅举几例。在接下来的章节中,我们将详细探讨这些库。除了这些库,我们还将使用开发工具,如 JupyterLab。你还会发现像 Stack Overflow 和 GitHub 这样的资源非常有价值。
总结
在这一章中,我们学习了自然语言的基础知识以及全球性考虑因素。我们还探讨了对话式人工智能与 NLP 之间的关系,并深入了解了交互式和非交互式应用。
在下一章中,我们将讨论选择 NLP 应用时需要考虑的因素。尽管这项技术有许多应用方式,但某些可能的应用对于当前的技术水平来说过于复杂。而其他看似适合 NLP 的应用,实际上可以通过更简单的技术来解决。在下一章中,你将学习如何识别这些应用。
第二章:识别实际的自然语言理解问题
本章将介绍如何识别适合当今技术的自然语言理解(NLU)问题。这意味着这些问题不会对当前最先进的 NLU 方法造成过大的挑战,但也不能通过简单的非-NLU 方法来解决。实际的 NLU 问题还需要足够的训练数据。如果没有足够的训练数据,最终的 NLU 系统将表现不佳。NLU 系统的好处也必须能够证明其开发和维护成本是合理的。尽管这些考虑事项主要是项目经理需要思考的内容,但它们同样适用于寻找课程项目或论文题目的学生。
在开始一个涉及 NLU 的项目之前,首先要问的问题是:项目的目标是否适合当前 NLU 技术的最先进水平?NLU 是解决你希望解决的问题的合适技术吗?这个问题的难度与当前 NLU 技术的水平相比如何?
在开始时,同样重要的是决定解决问题意味着什么。问题的解决程度可以有不同的标准。如果应用是一个课程项目、演示或概念验证,解决方案的准确性不必像为处理每天成千上万用户输入而设计的已部署解决方案那样高。同样,如果问题是一个前沿的研究问题,那么任何对当前技术状态的改进都是有价值的,即使该问题没有完全通过项目中的工作得到解决。解决方案的完整性需要达到什么程度是每个人在考虑自己想要解决的问题时需要做出的决定。
项目经理或负责做出技术决策的人员应该决定在项目完成时可接受的准确性水平,同时要记住,任何自然语言技术应用中都不太可能达到 100%的准确性。
本章将详细探讨如何识别适合应用 NLU 的实际问题。遵循本章讨论的原则,你将获得一个高质量、能够解决真实问题的有效系统。
本章涉及以下主题:
-
识别技术适用难度的问题
-
考虑困难的 NLU 应用
-
考虑不需要 NLP 的应用
-
训练数据
-
应用数据
-
考虑开发成本
-
考虑维护成本
-
决定 NLU 应用的流程图
识别技术适用难度的问题
注释
本章集中于技术性考虑问题。诸如是否存在市场需求、如何判断客户是否会对某个应用感兴趣等问题是很重要的,但它们超出了本书的范围。
这里列出了一些适合当前技术水平的问题类型。
今天的自然语言理解(NLU)在处理基于特定、具体主题的问题方面非常出色,例如以下示例:
-
将客户的产品评论分类为正面和负面评论:在线卖家通常会给买家提供评论他们购买的产品的机会,这对其他潜在买家以及卖家都有帮助。但是,大型在线零售商有成千上万的产品,因此面临着如何处理来自成千上万条评论的信息的问题。人工统计员无法阅读所有进入的评论,因此自动化的产品评论分类系统将非常有用。
-
回答有关账户余额或最近交易的基本银行问题:银行和其他金融机构拥有大型的客户服务中心来处理客户问题。通常,拨打电话的最常见原因是关于账户余额的简单问题,这些问题可以通过基于账户号码和账户类型的数据库查询来解答。一个自动化系统可以通过询问来电者他们的账户号码和所需信息的种类来处理这些问题。
-
进行简单的股票交易:买卖股票可能会变得非常复杂,但在许多情况下,用户只是想买或卖某个特定公司的一定数量的股票。这种交易只需要一些基本信息,例如账户号码、公司名称、股票数量以及买入或卖出的选择。
-
包裹追踪:包裹追踪只需要一个追踪号码即可告诉用户他们的包裹状态。虽然基于网络的包裹追踪很常见,但有时人们无法访问网络。通过自然语言应用,用户只需打个电话就能追踪包裹。
-
将客户问题路由到正确的客服代表:许多客户的问题只能由人工客服代表回答。对于这些客户,NLU 系统仍然很有帮助,它可以将来电者引导到正确部门的客服代表那里。它可以询问客户来电的原因,分类请求,然后自动将来电转接到处理该主题的专家或部门。
-
提供天气预报、体育比分和历史事实信息:这些类型的应用程序特点是请求有几个明确的参数。例如,对于体育比分,可能需要球队名称以及比赛日期。对于天气预报,参数包括位置和预报的时间框架。
所有这些应用的特点是它们都有明确且正确的答案。此外,系统预期理解的用户语言也不复杂。这些都是适合自然语言理解(NLU)项目的主题。
让我们通过更详细地讲解天气预报、体育成绩和历史事实的信息提供方式,来说明这些应用为何适合今天的技术。
图 2.1 显示了一个示例架构,用于提供不同城市的天气预报。当用户询问,“明天纽约市的天气预报是什么?”时,处理过程开始。请注意,用户发出了一个单一且简短的请求,要求提供特定信息——明天在特定地点的天气预报。自然语言理解系统需要检测意图(天气预报)、实体的位置和日期。这些都应该很容易找到——这些实体差异很大,而天气预报的意图不太可能与其他意图混淆。这使得自然语言理解系统能够轻松地将用户的提问转换为一个结构化的消息,供天气信息网络服务解释,如下图所示:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_02_01.jpg
图 2.1 – 一个实用的自然语言理解应用
尽管请求的信息并不复杂,但有很多不同的问法,这意味着仅仅列出可能的用户查询并不实际。表 2.1 展示了几种提出这个请求的方式:
“明天纽约市的天气预报是什么?”的几种改述 |
---|
明天纽约的天气会怎么样? |
明天纽约的天气怎么样? |
我想要纽约市明天的天气预报。 |
请告诉我明天纽约的天气。 |
明天纽约的天气预报。 |
明天纽约市的天气预报。 |
表 2.1 – 天气请求的改述
另一个使该应用适合自然语言理解的因素是,用户询问的信息(天气预报)可以通过多个易于访问的基于云的网络服务获得,这些服务的应用程序接口(APIs)通常有良好的文档支持。这使得开发者能够轻松向这些网络服务发送查询,并以结构化的形式获取用户请求的信息。然后,这些信息可以呈现给用户。开发者可以根据自己的需要选择展示方式——例如,文本、图形,或文本和图形的组合。
在图 2.1中,我们可以看到开发者选择通过自然语言呈现信息,因此使用了自然语言生成(NLG)组件,从表单中生成自然语言输出。其他展示选项包括显示图形,例如一个被云遮住的太阳图片,或者简单地显示来自天气信息网页服务的表单信息。然而,只有 NLG 选项适合语音或仅语音的界面,比如智能音响,因为在语音界面下无法显示图形。
NLU 在天气预报等应用中的最大好处是,它能够处理用户可能以相同意图提问的多种不同方式,如表 2.1所示。
表 2.1 展示了几种天气预报请求的不同表达方式。这些只是请求天气预报的几种可能方式的示例。令人惊讶的是,即便是简单的请求,也有许多不同的表达方式。如果我们能够列出所有选项,即使它是一个非常长的列表,NLU 也就不再是必需的了。
我们理论上可以列出所有可能性,并将它们映射到结构化查询。然而,实际上,很难预测一个人提出即使是简单的天气问题时,所有可能的提问方式。如果用户恰好以开发者未在列表中包含的方式表达查询,系统将无法响应。这会让用户感到困惑,因为他们不明白为什么类似的查询能成功,而这个查询却失败了。一个 NLU 系统能够应对更多查询变化。
正如我们在本节中所见,具有清晰且易于识别的意图和实体,并且能够从网络资源获取明确答案的应用,具有很大的成功机会,特别是使用今天的 NLU 技术。
现在,让我们转向一些不太可能成功的应用,因为它们需要超出当前技术水平的能力。
看看 NLU 的难度较大的应用。
我们如何判断某个问题是否对当前技术水平来说太难?首先,我们可以问,什么样的问题才算是太难。以下是尝试在超出当前技术水平的应用中使用 NLU 的一些后果:
-
系统将无法可靠地理解用户的查询。
-
答案将包含错误,因为系统误解了用户的查询。
-
系统将不得不频繁地说我不知道或我做不到,以至于用户感到沮丧并决定不再使用该应用。
重要的是要记住,技术水平正在迅速提高。最近,随着基于云的大语言模型(LLMs)如 ChatGPT 的出现,已经取得了显著进展。一些目前可能非常困难的应用,未来可能就不再那么困难了。
让我们看看今天一些难度较大的自然语言理解问题的特点。
需要系统做出判断或使用常识的应用程序
与前一节中的天气示例不同,要求做出判断的应用程序是那些没有唯一正确答案,甚至没有几个合理备选答案的应用。这些应用可能包括用户要求的建议,这些建议依赖于许多,通常是复杂的因素。以下是一些示例:
-
我应该学习 Python 吗?
-
我应该接种 COVID 疫苗吗?
-
我应该买电动汽车吗?
-
现在是买房的好时机吗?
要回答第一个问题,系统需要关于用户的具体知识(例如,用户是否已经有编程背景,或者他们希望用新学到的编程技能做什么)。基于大语言模型的系统,如 ChatGPT,将以一般的方式回答这些问题——例如,通过提供关于买房的普遍考虑因素——但它们无法提供针对用户的具体建议,因为它们不了解用户的任何信息。
系统被要求提供主观意见的应用程序也是非常难以处理的,例如以下这些示例:
-
有史以来最好的电影是什么?
-
谁是 20 世纪最有才华的演员?
-
有什么好方法可以在半小时内做鸡肉?
要完全回答这些类型的查询,需要系统拥有大量的常识性知识,例如,20 世纪有过职业生涯的演员。系统可以通过给出随机答案来回答主观性问题——例如,随便挑一部电影并说这部电影是有史以来最好的。但随机挑选的电影不一定好,更不用说是有史以来最好的电影了。
在这种情况下,如果有后续问题,系统将无法解释或为其观点辩护。所以,如果你问一个系统 我应该买电动汽车吗,并且它回答 是的,它将无法解释为什么回答是“是的”。事实上,今天的许多系统可能甚至没有意识到它们正在被问一个主观性问题。就像需要了解用户信息才能给出好答案的问题一样,基于大语言模型的系统会给出一般性的回答,但它们会承认自己无法处理主观性问题。
需要处理假设、可能性和反事实的应用程序
另一个难点是处理不真实或可能不真实的信息。当用户询问某件可能发生的事情,如果条件合适,用户实际上是在问一个假设或者可能性。今天最先进的系统擅长提供具体的、确凿的信息,但该技术不擅长推理关于可能性的内容。以下是一些示例:
-
如果我的预算是 15,000 美元,假设我愿意做一些自己动手的工作,那我应该能够建造多大的露台?
-
如果我有六个人,我应该买多少个披萨?
-
如果明天预报没有雨,提醒我浇水我的植物。
同样,系统在推理不真实的事情时也做得不太好。例如,考虑下面的句子,我想找一家附近的亚洲餐馆,但不要日本餐馆。为了正确回答这个问题,系统必须找到亚洲餐馆,并且要理解它应该排除日本餐馆,尽管它也是亚洲餐馆。
需要将语言信息与各种传感器信息结合的应用
一些非常有趣的应用可能涉及集成语言和摄像头或麦克风的信息。这些被称为多模态应用,因为它们集成了多种模态,如语音、图像以及非语音音频(如音乐):
-
这个蛋糕做好了吗?(举起相机对准蛋糕)
-
我的车发出的噪音是什么?(把麦克风对准引擎)
这些应用目前超出了现有商业自然语言技术的水平,尽管它们可以作为一个探索性研究项目的主题。它们目前也超出了 LLM 的能力范围,LLM 只能理解文本输入。
集成广泛的通用知识或专家知识的应用
当用户与自然语言理解(NLU)系统交互时,他们有一些希望达成的目标。在许多情况下,系统拥有用户没有的某种知识或专业技能,而用户希望利用这些专业技能。那么,这些专业知识来自哪里呢?为系统提供大量知识是非常困难的。现有的网络 API 可以提供一些简单信息,比如体育比分和天气情况。像 Wolfram Alpha 这样的系统也可以回答更复杂的问题,比如科学事实。
另一方面,回答需要使用专家知识的问题,比如医疗信息,要困难得多,因为没有易于获取的此类知识来源。此外,现有的信息来源可能是不一致的。一个显而易见的大量知识来源是万维网(WWW),它是 LLM 的主要知识来源。然而,WWW 上的知识可能是错误的、不一致的,或者不适用于特定情况,因此必须谨慎使用。
这些是今天自然语言技术面临的一些困难主题:
-
回答复杂的技术问题:像我无法连接到互联网这样的陈述要求系统拥有大量关于互联网连接的信息以及如何调试连接问题的信息。它还需要访问其他时间敏感的信息,比如用户所在地区是否有全球互联网中断。
-
回答涉及人际关系理解的问题:自从我开始和她的男朋友约会后,我的朋友就不理我了,我该怎么办? 系统必须了解大量的约会相关知识,可能还需要了解特定文化中的约会习俗,才能给出这样问题的合理答案。
-
读一本书并告诉我是否会喜欢这本书:现有的系统甚至很难阅读并理解一本完整的书籍,因为像书籍这样的长篇文本包含了非常复杂的信息。除了阅读一本书,系统要告诉我是否会喜欢这本书,还需要了解大量关于我和我的阅读兴趣的信息。
-
阅读一篇医学期刊文章并告诉我研究结果是否适用于我:回答这样的问题需要大量关于用户健康和病史的信息,并且还需要理解医学语言以及解读医学研究结果的能力。
-
理解笑话:理解笑话通常需要相当的文化知识。想一想,一个系统需要什么知识才能理解传统笑话为什么鸡要过马路?为了到另一边。这很好笑是因为问题让人以为鸡过马路有个有趣的理由,但它的理由实际上是非常明显的。要理解这个特定笑话为什么好笑对系统来说会非常困难,而且这只是一个笑话——仅仅理解这个笑话并不能帮助系统理解其他笑话。
-
解读比喻:我能吃下一匹马并不意味着你真想吃匹马,它只是意味着你非常饿。系统需要意识到这是一种比喻,因为马很大,没人能在一次进餐中吃掉一匹马,不管他多饿。另一方面,我能吃一块披萨则不是比喻,可能只是意味着用户想订一块披萨。
-
理解讽刺和挖苦:如果一本书评中写着作者真是个天才,评论者可能是字面意思上认为作者是天才,但也不一定。这句话可能是讽刺的意思,表示作者根本不是天才。如果这句话后面跟着我的三岁孩子写的书可能更好,我们就可以判断第一句话是讽刺的意思。自然语言理解(NLU)系统无法理解讽刺。它们也不知道三岁孩子不太可能写出好书,因此评论者的意思是这本书比三岁孩子写的还差,所以这本书很糟糕。
-
能够利用复杂的知识:以复杂知识为例,考虑以下说法,我的蛋糕像煎饼一样平,出了什么问题? 要回答这个问题,系统需要理解蛋糕不应该是平的,但煎饼通常是平的。它还必须理解我们讨论的是一个已经烤过的蛋糕,因为未烤过的蛋糕通常是平的。一旦系统搞清楚了这一点,它还需要理解足够的烘焙过程,以便给出关于蛋糕为何平的建议。
许多这类复杂应用所共有的一个特点是,往往没有任何单一的数据源可以提供答案。也就是说,开发人员无法简单地查询后端数据源来回答类似*现在买电动汽车合适吗?*这样的问题。这与之前天气预报的例子不同,在天气预报中,开发人员可以访问单一的后端数据源来获取答案。
与其试图找到单一的后端数据源,一种策略可能是通过网页搜索来寻找答案。但正如任何做过网页搜索的人所知道的那样,搜索结果会有成千上万(例如,关于“现在买电动汽车合适吗?”的搜索结果近 20 亿条),而且更糟糕的是,答案之间不太可能一致。有些页面会断言现在是购买电动汽车的好时机,其他页面则会断言现在并不适合购买。因此,单纯依赖网页搜索来回答没有明确数据源的问题可能行不通。然而,能够整合来自网页的多方面信息正是大语言模型(LLM)的强项,因此,如果信息在网络上可用,像 ChatGPT 这样的 LLM 将能够找到它。
用户经常不知道自己想要什么的应用场景
用户并不总是能非常明确地表述他们的意图。举个例子,想象一个游客正在访问一个陌生的城市。也许这个城市提供一种服务,游客可以打电话了解公共交通选项。如果游客问一个问题,比如从万豪酒店到 123 市场街应该坐哪趟火车?,字面上的回答可能是你不能从万豪酒店乘坐火车到 123 市场街。或者,系统可能会提供一条绕远的路线,耗时六小时。
一位人类接线员可能会意识到,来电者的实际目标很可能是从万豪酒店到 123 市场街,而提到火车只是来电者猜测火车是一个好的交通方式。在这种情况下,人类接线员可能会说类似这样的话:这两个地点之间并没有很好的火车路线;你想了解其他的交通方式吗? 这种对话对人类接线员来说是自然的,但对于自动化系统来说非常困难,因为系统需要能够推理出用户的真实目标。
需要理解多种语言的应用
正如在第一章中讨论的,某些语言的语言技术比其他语言更为先进。如果一个系统需要能够与用户进行不同语言的交流(通过语音或文字),那么就必须为每种语言开发语言模型。对某些语言的处理将比其他语言更准确,而对于某些语言,处理可能根本不够好。在当前的技术水平下,针对主要的欧洲、中东和亚洲语言,NLP 技术应该能够处理大多数应用。
在某些应用程序中,系统必须根据用户的语言选择与其对话。这就要求系统能够仅通过声音或单词分辨出不同的语言。这项技术叫做语言识别。识别常见语言并不困难,但对于不常见的语言,情况则不同。
对于训练数据非常少的语言,如讲者少于一百万的语言,该语言可能没有被足够研究,导致无法为该语言开发自然语言应用程序。
比理解多种语言更困难的是处理两种或更多语言在同一句子中的混合情况。这种情况通常发生在同一地区讲多种语言的地方,人们假设他们与之交谈的任何人都能理解所有本地语言。将不同语言混合在同一句子中称为代码切换。处理包含代码切换的句子比处理多个语言的句子更加困难,因为系统必须为句子中任何位置出现的任何语言的单词做好准备。这对当前的技术来说是一个难题。
在前面的讨论中,我们回顾了许多让应用程序在当今自然语言处理(NLP)技术下过于复杂的因素。现在,让我们来看看那些过于简单的应用程序。
看看那些不需要 NLP 的应用程序
由复杂的应用程序转向过于简单的应用程序,我们还可以看看那些解决方案比 NLP 更简单的应用程序——即,应用 NLP 的解决方案反而过于复杂的应用程序。这些是问题的复杂性不需要通过构建和管理自然语言系统来解决的应用场景。
自然语言的特点是输入不可预测,且单词与意义之间没有直接的对应关系。不同的单词可以表达相同的意义,而相同的单词也可以根据上下文表达不同的意义。如果输入和意义之间有简单的一一映射,那么就不需要 NLP 技术。
可以通过正则表达式分析的文本
第一个不需要自然语言理解(NLU)的情况是当可能的输入由一组有限的选项组成时,如城市、州或国家。内部,这些输入可以表示为列表,并通过查表的方式进行分析。即使某些输入有同义词(例如,UK 代表 United Kingdom),这些同义词也可以被包含在列表中。
一个稍微复杂一点,但仍然简单的输入是当系统的每个输入都按照简单明了、不变的规则组成时。在这种情况下不需要自然语言处理(NLP),因为输入是可以预测的。这些简单表达的一个好例子是电话号码,它们有固定且可预测的格式,或者是日期,它们虽然更多样,但依然有限。除了这些通用表达,在特定的应用中,通常还需要分析诸如产品 ID 或序列号之类的表达式。这些类型的输入可以通过正则表达式进行分析。正则表达式是描述字符模式(字母、数字或特殊字符)的规则。例如,^\d{5}(-\d{4})?$
这个正则表达式可以匹配美国邮政编码,它可以是五位数字(12345
),也可以是五位数字后跟一个连字符,然后是四位数字(12345-1234
)。
如果应用中的所有输入都属于这些固定的短语类型,正则表达式可以完成工作,而不需要全套的 NLP。如果整个问题都可以通过正则表达式解决,那么就不需要 NLP。如果只有部分问题可以通过正则表达式解决,而另一部分需要 NLP,则可以将正则表达式与自然语言处理技术结合使用。例如,如果文本中包含格式化的数字,如电话号码、邮政编码或日期,可以使用正则表达式仅分析这些数字。如果应用中需要正则表达式,Python 有很好的库来处理正则表达式。我们将在第八章和第九章中讨论如何将 NLP 与正则表达式结合使用。
从已知的词汇列表中识别输入
如果唯一可用的输入来自一组固定的可能性,则不需要 NLP。例如,如果输入只能是一个美国州名,则应用程序可以直接查找州名。如果输入包括来自固定可能性集合的词汇,但还有周围的词汇,这时就会稍微复杂一些。这种情况叫做关键词识别。当所需的响应来自一个固定词汇集(例如 50 个州的名称之一),并且用户有时会添加一些东西时,就会发生这种情况——例如,用户在系统提问如你住在哪里?时,回答说我住在亚利桑那。
这可能不需要 NLP——系统只需要能够忽略无关的词语(在这个例子中是 I live in)。可以通过使用 *
来编写正则表达式,以匹配任意数量的字符,包括零个字符,来忽略无关的词语。Python 使用 +
来匹配至少一个字符。因此,在 Python 中,查找关键字 Arizona
的正则表达式就是 *Arizona*
。
使用图形界面
大多数应用程序依赖于图形用户界面,用户通过从菜单中选择选项和点击按钮来与应用程序互动。这些传统的界面比基于 NLU 的界面更容易构建,并且适用于许多应用程序。那么,在什么情况下基于 NLU 的界面更合适呢?
NLU 是更好的选择,因为用户需要提供的信息变得更加详细。当这种情况发生时,图形界面必须依赖更深层次的菜单,要求用户通过一个又一个菜单进行导航,直到找到所需的信息,或者直到应用程序收集到足够的信息来回答他们的问题。这在移动界面上尤为突出,因为屏幕上能够显示的信息比笔记本或台式计算机上能显示的信息要少得多,这意味着菜单需要有更深的层级。另一方面,NLU 输入允许用户只需一次说明他们的目标,而无需通过多个菜单进行导航。
图形界面中深层菜单的另一个问题是,菜单中使用的术语并不总是与用户对其目标的心理模型相匹配。这些不匹配可能会导致用户走上错误的路径。他们可能直到菜单树的几层之后才意识到自己的错误。当这种情况发生时,用户必须从头开始。
图形界面和 NLP 应用程序之间的对比可以在包含传统图形界面和 NLP 聊天机器人的网站和应用程序中轻松看到。在这些界面中,用户可以在基于菜单的导航和与聊天机器人互动之间进行选择。一个很好的例子是 Microsoft Word 2016 界面。Word 是一个非常复杂的应用程序,功能丰富。为这样一个复杂的应用程序制作直观的图形界面是困难的,而且用户可能很难找到他们正在寻找的信息。
为了解决这个问题,微软提供了图形界面和 NLP 界面两种方式来实现 Word 功能。在 Word 文档页面顶部,有一个选项,选择如何添加公式
会列出几种不同的方式来将公式添加到 Word 文档中。这比在嵌套菜单中查找要快捷得多,直接得多。
当菜单层级超过三层时,开发人员应该考虑在图形应用程序中添加 NLU 功能,尤其是当每个菜单层级包含很多选择时。
到目前为止,我们已经讨论了影响应用是否适合自然语言处理技术的许多因素。接下来的考虑因素与开发过程相关——数据的可用性以及开发过程本身,我们将在接下来的章节中讨论。
确保有足够的数据可用
在确定问题是否适合自然语言理解(NLU)之后,我们可以转向下一个问题——为了解决这个问题,哪些类型的数据是可用的?是否有现有数据?如果没有,获取解决问题所需数据的过程是什么?
我们将讨论两种数据。首先,我们将考虑训练数据,即 NLU 系统用户使用的语言类型的示例,并且我们将研究训练数据的来源。第二种数据是我们将讨论的应用数据。本节中的信息将帮助你确定是否有足够的训练数据,以及将其正确格式化以用于 NLU 系统开发过程需要多少工作。
应用数据是系统用来回答用户问题的信息。正如我们将看到的,它可以来自公开的来源,也可以来自内部数据库。对于应用数据,我们将看到,确保数据可用、可靠且可以在不产生过高成本的情况下获取是非常重要的。
训练数据
自然语言应用几乎都基于它们预计处理的输入类型的示例进行训练。这意味着,任何自然语言应用要成功,必须有足够的训练数据。如果没有足够的训练数据,当应用被部署时,会出现无法处理的输入,因为系统在开发阶段没有接触过类似的输入。这并不意味着系统在训练时需要看到每一个可能的输入。尤其是对于较长或复杂的文档,如产品评论,这几乎是不可能的。
同一条评论发生两次的可能性极低。相反,训练过程的设计是为了使语义相似的文档以相同的方式进行分析,即使具体的单词和措辞有所不同。
机器学习算法,如我们将在第九章和第十章中学习的算法,通常需要大量数据。需要区分的类别或意图越多,所需的数据量也越大。大多数实际应用需要成千上万的训练示例。
除了示例,通常训练数据还必须包括正确答案,即训练好的系统应该如何分析数据。正确答案的技术术语是标注。标注也可以被称为真实值或黄金标准。例如,如果应用程序的设计目的是判断产品评论是正面还是负面,标注(由人工评审提供)会为一组评论分配正面或负面标签,这些评论将用作训练和测试数据。
表 2.2 显示了产品评论的正面和负面示例及其标注。一个准确的产品评论分类系统可能需要基于几千条产品评论。在某些情况下,就像表 2.2中的示例一样,标注任务并不需要任何特别的专业知识;几乎任何英语掌握得较好的人都可以判断产品评论是正面还是负面。这意味着简单的标注任务可以通过低成本的众包方式完成。
另一方面,一些标注需要由领域专家来完成。例如,标注复杂软件产品的交互式故障排除对话数据,可能需要由具有该产品专业知识的人来做。这会使标注过程变得更加昂贵,如果所需的专家无法获得,这甚至可能变得不可能:
文本 | 标注 |
---|---|
我对这款产品感到非常失望。它很脆弱,价格过高,而且油漆脱落。 | 负面 |
这款产品完全符合我的期望。它做工精良,外观漂亮,价格合理。我毫无保留地推荐给任何人。 | 正面 |
表 2.2 – 产品评论的正面和负面标注示例
虽然数据标注可能既困难又昂贵,但并非所有的自然语言理解(NLU)算法都需要标注数据。特别是我们将在第十二章讨论的无监督学习,就是基于未标注的数据。在第十二章中,我们还将讨论未标注数据的局限性。
一个应用程序的完整训练示例集称为语料库或数据集。为了使应用程序准确,必须拥有足够的训练数据。训练数据不需要一次性全部可用——开发可以在数据收集完成之前开始,并且可以在开发过程中添加额外的数据。如果标注人员忘记了他们用于标注早期数据的标准,这可能会导致一致性问题。
数据来自哪里?Python 的 NLP 库包含几个玩具数据集,可以用于测试系统设置或算法,或者可以用于学生项目,在这些项目中并不打算将系统投入生产。此外,还可以从像 Hugging Face(https://huggingface.co/)或语言数据联盟(Linguistic Data Consortium,https://www.ldc.upenn.edu/)这样的组织获得更大的数据集。
对于企业应用程序,来自先前由人工代理执行的早期应用程序的数据可能非常有用。一个例子可能是客服通话记录。
另一个很好的数据来源是数据库的文本字段。例如,这可能是你期望找到某个组织产品的产品评论的地方。在许多情况下,数据库的文本字段旁边会有另一个手动分类字段,用于标识评论是正面的还是负面的。例如,这种手动分类实际上是一种标注,可以用于训练过程,创建一个能够自动分类产品评论的系统。
最后,新的数据也可以专门收集以支持应用程序。这可能既费时又昂贵,但有时这是获得适当数据的唯一方法。数据收集本身可能是一个复杂的话题,特别是当数据被收集以支持与人类用户的互动对话时。
数据,包括数据收集,将在第五章中详细讨论。
应用程序数据
除了训练自然语言应用程序所需的数据外,还需要考虑与访问系统将提供的信息相关的任何成本。
许多第三方网络服务提供开发者可以访问的 API,用于获取免费的或付费的信息。有些网站提供有关可用公共 API 的通用信息,例如APIsList(https://apislist.com/)。该网站列出了可提供涵盖数百个类别的数据的 API,包括天气、社交网络、地图、政府、旅行等。许多 API 需要付费,无论是订阅费用还是按交易收费,因此在选择应用程序时,考虑这些潜在费用非常重要。
考虑开发成本
在确保数据可用,并且数据已(或可以)标注所需的意图、实体和分类类别后,决定自然语言处理(NLP)是否适合某个应用程序的下一个考虑因素是开发应用程序本身的成本。一些技术上可行的应用程序,尽管如此,仍然可能因开发成本过高、风险过大或耗时过长而变得不切实际。
开发成本包括确定针对特定问题最有效的机器学习方法。这可能需要大量时间,并且需要一些试验和错误的过程,因为在探索不同算法的过程中,模型需要不断训练和重新训练。确定最有前景的算法也可能需要 NLP 数据科学家,而这些人才可能会很稀缺。开发人员必须问自己,开发成本是否与最终应用程序将带来的收益相匹配。
对于低流量的应用,必须记住,开发和部署 NLP 解决方案的成本可能超过雇佣人工执行相同任务的成本。特别是如果即便实施了 NLP 解决方案并且已经承担部分工作,仍然需要一些人工来完成更复杂的任务时,这一点尤为成立。
考虑维护成本
对于自然语言应用程序,尤其是部署后的应用程序,最后需要考虑的因素是维护成本。这一点容易被忽视,因为自然语言理解(NLU)应用有一些传统应用所没有的维护考虑因素。具体来说,某些应用程序中使用的语言类型随着时间的推移而变化。这是可以预见的,因为它反映了用户讨论内容的变化。例如,在客户服务应用中,产品名称、商店位置和服务可能会发生变化,有时变化非常迅速。客户用于询问这些信息的新词汇也会随之变化。这意味着需要将新词汇添加到系统中,并且机器学习模型必须重新训练。
类似地,提供快速变化信息的应用程序需要持续进行更新。例如,“COVID-19”这个词在 2020 年初被引入——那时没有人听说过这个词,但现在它已经广为人知。由于关于 COVID-19 的医疗信息变化非常迅速,设计用于提供 COVID-19 信息的聊天机器人必须非常小心地进行维护,以确保它保持最新,并且不会提供错误甚至有害的信息。
为了保持应用程序与用户话题的同步,需要规划三个特定于自然语言应用的任务:
-
开发人员需要负责将应用程序保持最新,以便随着新信息(如新产品或新产品类别)加入系统。
-
应该经常审查平台提供的用户输入日志。对于处理不当的用户输入,必须进行分析,以确定正确的处理方式。用户是否在询问新的话题(意图)?如果是这样,必须添加新的意图。用户是否在以不同的方式讨论现有话题?如果是这种情况,则需要为现有的意图添加新的训练示例。
-
当发现问题并且用户输入未正确处理时,系统需要进行修改。最简单的修改类型是添加新词汇,但在某些情况下,可能需要更结构性的更改。例如,可能需要将现有的意图拆分为多个意图,这意味着必须重新审查原始意图的所有训练数据。
保持应用程序更新所需的开发人员数量取决于几个因素:
-
用户输入的数量:如果系统每天收到数百或数千个失败的输入,就需要分配开发人员来审查这些输入,并向系统添加信息,以便系统能够处理这些输入。
-
应用程序的复杂性:如果应用程序包含数百个意图和实体,那么就需要更多的开发人员来保持其更新,并确保任何新信息与旧信息保持一致。
-
应用程序提供的信息波动性:如果应用程序是一个不断添加新词、新产品和新服务的系统,那么为了保持最新状态,系统将需要更频繁的更新。
这些成本是额外的,除了任何与自然语言应用程序无关的硬件或云服务成本。
决定 NLU 应用程序的流程图
本章已经涵盖了在决定使用 NLP 应用程序时应考虑的许多因素。
图 2.2 总结了这些考虑因素,呈现为评估潜在 NLU 应用程序的流程图。
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_02_02.jpg
图 2.2 – 评估 NLU 项目的步骤
从顶部开始,首先要问的问题是,当前的技术水平是否使问题太难或太容易解决,如前面讨论的标准。如果问题过难或过易,我们应该寻找其他应用程序,或考虑缩小或扩大应用范围,使其更适合 NLP 技术。例如,应用程序可能会被重新设计,以支持更少的语言。
如果问题看起来适合当前的技术水平,下一步是确保是否有适当的数据可用,如果没有,是否可以收集数据。一旦数据可用,接下来的事情就是查看开发和维护的成本是否合理。如果一切顺利,应用程序的开发可以继续。
总结
本章中,我们讨论了选择那些在当前 NLP 技术下有较高成功可能性的 NLP 应用程序。成功的应用程序通常具有特定的、客观的输入答案,具有可用的训练数据,并且处理(最多)几种语言。
本章特别解答了许多重要问题。我们学习了如何识别与当前自然语言理解技术水平相适应的适当难度问题。我们还学会了如何确保系统开发所需的数据足够,并且如何估算开发和维护成本。
学习如何评估不同类型的 NLP 应用的可行性,将对你推进 NLP 项目极有价值。选择一个过于雄心勃勃的应用会导致挫败和项目失败,而选择一个对现有技术水平来说过于简单的应用,则会浪费时间并导致不必要的复杂系统。
我们已经达成了学习如何评估 NLP 项目可行性的目标,考虑的标准包括技术可行性以及数据可用性和维护成本等实际因素。
在下一章中,我们将介绍 NLP 的主要方法以及每种方法的优缺点。这些方法包括基于规则的系统,在这种系统中,人类专家编写规则描述系统应如何分析输入,以及机器学习,在机器学习中,系统通过处理大量输入示例及其分析方式来进行训练。
第二部分:开发与测试自然语言理解系统
完成本节内容后,你将能够决定哪些技术适用于解决自然语言理解技术中的问题,并使用 Python 和 Python 库(如 NLTK、spaCy 和 Keras)实现系统并进行评估。
本部分包括以下章节:
-
第三章,自然语言理解方法 – 基于规则的系统、机器学习和深度学习
-
第四章,为自然语言理解选择库和工具
-
第五章,自然语言数据 – 寻找和准备数据
-
第六章,探索和可视化数据
-
第七章,选择方法与表示数据
-
第八章,基于规则的技术
-
第九章,机器学习第一部分 – 统计机器学习
-
第十章,机器学习第二部分 – 神经网络与深度学习技术
-
第十一章,机器学习第三部分 – Transformer 与大语言模型
-
第十二章,应用无监督学习方法
-
第十三章,它的效果如何?– 评估
第三章:自然语言理解方法 – 基于规则的系统、机器学习和深度学习
本章将回顾最常见的自然语言理解(NLU)方法,并讨论每种方法的优缺点,包括基于规则的技术、统计技术和深度学习。还将讨论流行的预训练模型,如**双向编码器表示来自变换器(BERT)**及其变体。我们将了解到,自然语言理解并非单一的技术,它包括一系列可用于不同目标的技术。
本章将涵盖以下主要内容:
-
基于规则的方法
-
传统的机器学习方法
-
深度学习方法
-
预训练模型
-
选择技术时的考虑因素
让我们开始吧!
基于规则的方法
基于规则的方法的基本思想是,语言遵循关于单词与其含义之间关系的规则。例如,当我们学习外语时,我们通常会学习有关单词含义的特定规则,了解它们在句子中的排列方式,以及前缀和后缀如何改变单词的意义。基于规则的自然语言理解方法的运作前提是,可以为自然语言理解系统提供这些类型的规则,从而使系统能够像人类一样确定句子的含义。
基于规则的方法在自然语言理解(NLU)中广泛应用,从 1950 年代中期到 1990 年代中期,直到基于机器学习的方法变得流行。然而,仍然有一些自然语言理解问题,基于规则的方法仍然有用,无论是单独使用,还是与其他技术结合使用。
我们将首先回顾与语言各个方面相关的规则和数据。
单词与词汇表
几乎每个人都熟悉单词的概念,单词通常被定义为可以单独发音的语言单位。正如我们在第一章中看到的,在大多数但并非所有语言中,单词通过空格分隔。语言中的单词集合被称为该语言的词汇表。词汇表的概念与我们所认为的字典相对应——它是语言中单词的列表。计算机词汇表还包括有关每个单词的其他信息,特别是它的词性。根据语言的不同,它还可能包括该单词是否有不规则形式的信息(例如,对于不规则的英语动词“eat”,其过去式“ate”和过去分词“eaten”是不规则的)。有些词汇表还包括语义信息,如与每个单词含义相关的词语。
词性标注
学校中教授的传统词性包括“名词”、“动词”、“形容词”、介词等类别。计算词典中使用的词性通常比这些更为详细,因为它们需要表达比传统类别能够捕捉到的更具体的信息。例如,英语中传统的动词类别通常被细分为几个不同的词性,分别对应动词的不同形式,如过去式和过去分词。一个常用的英语词性集是来自 Penn Treebank 的词性(catalog.ldc.upenn.edu/LDC99T42
)。不同的语言在其计算词典中会有不同的词性类别。
处理自然语言时,一个非常有用的任务是为文本中的单词分配词性。这被称为词性标注(POS 标注)。表 3.1展示了句子“We would like to book a flight from Boston to London”中,Penn Treebank 词性标签的一个示例:
单词 | 词性 | 词性标签的含义 |
---|---|---|
we | PRP | 人称代词 |
would | MD | 情态动词 |
like | VB | 动词,基本形式 |
to | TO | 不定式(该词有其独立的词性) |
book | VB | 动词,基本形式 |
a | DT | 限定词(冠词) |
flight | NN | 单数名词 |
from | IN | 介词 |
Boston | NNP | 专有名词 |
to | TO | 不定式 |
London | NNP | 专有名词 |
表 3.1 – 句子“We would like to book a flight from Boston to London”的词性标注
词性标注不仅仅是查字典并为单词标注词性,因为许多单词有多个词性。在我们的示例中,其中一个就是“book”,在这个例子中它作为动词使用,但也常作为名词使用。词性标注算法不仅要看单词本身,还要考虑它的上下文,以确定正确的词性。在这个例子中,“book”跟随在“to”之后,而“to”通常表示下一个单词是动词。
语法
语法规则是描述单词在句子中如何排列的规则,以便句子能够被理解,并且能够正确传达作者的意思。它们可以用描述句子及其成分之间部分-整体关系的规则来书写。例如,英语中的一个常见语法规则是句子由名词短语后跟动词短语组成。任何自然语言的完整计算语法通常由数百条规则组成,非常复杂。现在从零开始构建语法并不常见;相反,语法通常已经包含在常用的 Python 自然语言处理库中,如自然语言工具包(NLTK)和spaCy。
解析
找出句子各部分之间的关系称为解析。这涉及应用语法规则来分析特定句子,展示句子各部分是如何相互关联的。图 3.1展示了句子“We would like to book a flight”的解析。在这种解析风格中,称为依存解析,单词之间的关系通过连接单词的弧线来表示。例如,“we”是动词“like”的主语,这一事实通过标记为nsubj的弧线将“like”与“we”连接起来。
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_03_01.jpg
图 3.1 – “We would like to book a flight”句子的解析
在此阶段,不必担心解析的细节——我们将在第八章中详细讨论。
语义分析
解析涉及确定单词在句子中的结构性关系,但它不涉及单词的意义或意义之间的关系。这类处理通过语义分析来完成。语义分析有很多方法——这是一个活跃的研究领域——但一种思路是,语义分析从句子的主要动词开始,查看动词与句子中其他部分(如主语、直接宾语和相关介词短语)之间的关系。例如,图 3.1中,“like”的主语是“We”。“We”可以描述为“like”的“experiencer”,因为它被描述为经历“liking”的动作。类似地,被喜欢的事物“to book a flight”可以描述为“like”的“patient”。语义分析最常见的做法是应用规则,但也可以通过机器学习技术来完成,下一节将进行介绍。
在不考虑词语在句子中的角色的情况下,找到表示词汇概念之间的语义关系也是有用的。例如,我们可以将“dog”看作是“animal”的一种,或者我们可以将“eating”看作是一种动作。一个有助于找到这类关系的资源是 Wordnet(wordnet.princeton.edu/
),它是一个大型的手工构建数据库,描述了成千上万的英语单词之间的关系。图 3.2展示了“airplane”这个词的部分 Wordnet 信息,表明飞机是“heavier-than-aircraft”的一种,而“heavier-than-aircraft”是“aircraft”的一种,依此类推,一直到非常一般的类别“entity”。
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_03_02.jpg
图 3.2 – “airplane”一词的 Wordnet 语义层级
实用分析
语用分析确定词语和短语在上下文中的意义。例如,在长篇文本中,不同的词可以用来指代相同的事物,或者不同的事物可以用相同的词来指代。这被称为共指。例如,句子“We want to book a flight from Boston to London”后面可能跟着“the flight needs to leave before 10 a.m.”语用分析确定需要在上午 10 点之前起飞的航班就是我们想要预订的航班。
一种非常重要的语用分析方法是命名实体识别(NER),它将文本中出现的引用与现实世界中对应的实体关联起来。图 3.3展示了对句子“Book a flight to London on United for less than 1,000 dollars”的 NER 分析。“London”是一个命名实体,被标记为地理位置,“United”被标记为组织,“less than 1,000 dollars”被标记为货币金额:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_03_03.jpg
图 3.3 – “Book a flight to London on United for less than 1,000 dollars” 的 NER 分析
管道
在自然语言处理应用中,我们刚才描述的步骤通常作为管道来实现;即一系列步骤,其中一个步骤的结果是下一个步骤的输入。例如,一个典型的 NLP 管道可能如下所示:
-
词汇查找:在应用程序的字典中查找词语
-
词性标注:为每个词在上下文中分配词性
-
句法分析:确定词语之间的关系
-
语义分析:确定单词的意义及句子的整体意义
-
语用分析:确定依赖于更广泛上下文的意义方面,例如代词的解释
使用管道的一个优点是每个步骤可以使用不同的技术来实现,只要该步骤的输出格式符合下一个步骤的预期格式。因此,管道不仅在基于规则的方法中有用,也在我们将在接下来的部分描述的其他技术中有用。
有关基于规则技术的更多细节将在第八章中提供。
我们现在将转向那些不那么依赖语言规则,而更多依赖机器学习与现有数据的技术。
传统的机器学习方法
虽然基于规则的方法提供了非常精细和具体的语言信息,但这些方法也存在一些缺点,这促使了替代方法的发展。主要有两个缺点:
-
开发用于基于规则的方法的规则可能是一个繁琐的过程。规则开发可以由专家直接编写规则,基于他们对语言的理解,或者更常见的是,规则可以从标注了正确分析的文本示例中推导出来。这两种方法都可能是昂贵且耗时的。
-
规则不太可能普遍适用于系统遇到的每个文本。制定这些规则的专家可能忽视了一些情况,标注的数据可能没有覆盖每种情况的示例,且说话者可能会犯错,如错误的开始,尽管这些错误没有被任何规则覆盖,但仍需分析。书面语言可能包含拼写错误,从而导致一些词汇不在词汇表中。最后,语言本身可能会发生变化,产生新的单词和短语,而这些新词和新短语并不在现有规则中涵盖。
出于这些原因,基于规则的方法主要作为自然语言理解(NLU)管道的一部分使用,补充其他技术。
传统的机器学习方法受到分类问题的驱动,在这些问题中,相似意思的文档可以被分组。分类问题中需要解决两个问题:
-
以某种方式表示训练集中的文档,使得同一类别中的文档具有相似的表示
-
决定如何根据与训练集中文档的相似度对新的、先前未见过的文档进行分类
表示文档
文档的表示是基于单词的。一种非常简单的方法是假设文档应该仅仅通过它包含的单词集合来表示。这种方法被称为词袋模型(BoW)。使用 BoW 进行文档表示的最简单方法是列出语料库中的所有单词,然后对于每个文档和每个单词,指出该单词是否出现在该文档中。
例如,假设我们有一个由三个文档组成的语料库,如图 3.4所示:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_03_04New.jpg
图 3.4 – 小型餐厅查询语料库
这个玩具语料库的整个词汇表包含 29 个词,因此每个文档都与一个长度为 29 的列表相关联,列表中指出了每个单词是否出现在该文档中。这个列表将出现表示为1
,将未出现表示为0
,如表 3.2所示:
a | an | any | are | aren’t | away | Chinese | Eastern | … | |
---|---|---|---|---|---|---|---|---|---|
1 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | … |
2 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | … |
3 | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | … |
表 3.2 – 小语料库的词袋模型(BoW)
表 3.2 显示了这三份文档中词汇表前八个单词的词袋(BoW)列表。表 3.2中的每一行代表一个文档。例如,单词“a”在第一个文档中出现一次,但单词“an”没有出现,因此其条目是0。这种表示在数学上是一个向量。向量是 NLU 中的一种强大工具,我们将在后面详细讨论它们。BoW 表示法可能看起来非常简单(例如,它没有考虑单词的顺序信息)。然而,这一概念的其他变种更为强大,稍后将在第九章至第十二章中讨论。
分类
BoW 方法背后的假设是,两个文档中共享的单词越多,它们的意义就越相似。这不是一条硬性规则,但事实证明,在实践中非常有用。
对于许多应用,我们希望将含义相似的文档分组到不同的类别中。这就是分类的过程。如果我们想将一个新文档分类到这些类别中的某一类,我们需要找出它的向量与每个类别中其他文档的向量的相似度。例如,在第一章中讨论的情感分析任务,就是将文档分类为两类——关于文本主题的积极或消极情感。
已经使用了许多算法来对文本文件进行分类。朴素贝叶斯和支持向量机(SVMs),将在第九章中讨论,是其中最受欢迎的两种。神经网络,特别是递归神经网络(RNNs),也很受欢迎。神经网络将在下一节简要讨论,并将在第十章中详细讨论。
在本节中,我们总结了一些在传统机器学习中使用的方法。现在,我们将把注意力转向基于深度学习的新方法。
深度学习方法
神经网络,特别是通常称为深度学习的大型神经网络,近年来在自然语言理解(NLU)中变得非常流行,因为它们显著提高了早期方法的准确性。
神经网络的基本概念是,它们由多个连接单元的层组成,这些单元被称为神经元,类似于动物神经系统中的神经元。神经网络中的每个神经元都与其他神经元相连接。如果一个神经元从其他神经元接收到适当的输入,它将被激活,或者将输入发送到另一个神经元,而后者则会根据接收到的其他输入决定是否激活。在训练过程中,会调整神经元上的权重,以最大化分类准确性。
图 3.5 显示了一个四层神经网络执行情感分析任务的示例。神经元是由线连接的圆圈。最左边的第一层接收文本输入,接着两个隐藏层的神经元处理该输入,最终的输出层中的单个神经元给出结果(正面):
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_03_05.jpg
图 3.5 – 一个四层神经网络,用于对产品评论进行情感分析
尽管神经网络背后的概念已经存在多年,但能够执行重大任务的大型神经网络的实现直到最近几年才得以实现,这得益于之前计算资源的限制。它们目前的流行性主要是因为它们通常比早期的方法更准确,特别是在有足够的训练数据的情况下。然而,训练一个神经网络以执行大规模任务的过程可能非常复杂且耗时,并且可能需要专家数据科学家的帮助。在某些情况下,神经网络所提供的额外准确性不足以证明开发该系统的额外成本是合理的。
深度学习和神经网络将在第十章中详细讨论。
预训练模型
最新的自然语言理解方法基于这样的理念:理解自然语言所需的许多信息,可以通过处理通用文本(如互联网文本)来为多个不同的应用提供,从而创建一个语言的基准模型。这些模型中的一些非常庞大,基于大量的数据。为了将这些模型应用于特定的应用,通用模型通过使用特定应用的训练数据进行适应,这一过程被称为微调。由于基准模型已经包含了大量关于语言的通用信息,因此所需的训练数据量通常比某些传统方法所需的训练数据少得多。这些流行的技术包括 BERT 及其许多变种,以及生成预训练变换器(GPTs)及其变种。
预训练模型将在第十一章中详细讨论。
选择技术时的考虑因素
本章介绍了四类自然语言理解技术:
-
基于规则的
-
统计机器学习
-
深度学习和神经网络
-
预训练模型
我们应该如何决定应该采用哪种技术或技术组合来解决特定问题呢?这些考虑因素主要是实际性的,涉及到创建可行解决方案所需的成本和努力。让我们来看一下每种方法的特点。
表 3.3 列出了我们在本章中回顾的四种自然语言理解(NLU)方法,并对它们在开发者专业知识、所需数据量、训练时间、准确性和成本方面进行了比较。如 表 3.3 所示,每种方法都有优点和缺点。对于那些不需要大量数据的小型或简单问题,基于规则的、深度学习或预训练方法应该被强烈考虑,至少可以作为管道的一部分。虽然预训练模型准确性高,且开发成本相对较低,但开发者可能更倾向于避免使用云服务或管理本地计算资源上的大型模型的成本。
开发者 专业知识 | 所需数据量 | 训练时间 | 准确性 | 成本 | |
---|---|---|---|---|---|
基于规则的 | 高(语言学家或领域专家) | 少量领域特定数据 | 专家写规则需要大量时间 | 如果规则准确,成本高 | 规则开发可能成本较高;计算机时间成本较低 |
统计方法 | 中等 - 使用标准工具;需要一些 NLP/数据科学专业知识 | 中等量的领域特定数据 | 大量的标注时间 | 中等 | 数据标注可能成本较高;计算机时间成本较低 |
深度学习 | 高(数据科学家) | 大量领域特定数据 | 大量标注时间;训练模型需要额外的计算时间 | 中等偏高 | 一些云服务或本地计算资源的费用 |
预训练模型 | 中等 - 使用标准工具,具备一定的数据科学专业知识 | 少量领域特定数据 | 中等量的时间标注数据以微调模型 | 高 | 一些云服务或本地计算资源的费用 |
表 3.3 – NLU 一般方法的比较
最重要的考虑因素是所要解决的问题以及可接受的成本。还应记住,选择某种技术并不是一个永久性的承诺,特别是对于那些依赖标注数据的方法,这些数据可以被用于多种方法。
小结
在本章中,我们概述了可以在 NLU 应用中使用的各种技术,并学到了几个重要的技能。
我们学习了基于规则的方法是什么,以及主要的基于规则的技术,包括词性标注和句法分析等主题。接着,我们学习了重要的传统机器学习技术,特别是文本文件如何进行数字化表示的方法。然后,我们关注了现代深度学习技术的优缺点以及预训练模型的优势。
在下一章中,我们将回顾开始进行自然语言理解(NLU)所需的基础知识——安装 Python,使用 Jupyter Labs 和 GitHub,使用 NLU 库(如 NLTK 和 spaCy),以及如何在这些库之间进行选择。
第四章:选择自然语言理解的库和工具
本章将帮助你设置处理自然语言的环境。我们将首先讨论如何安装 Python,然后讨论一些常用的开发工具,如 JupyterLab 和 GitHub。我们还将回顾几个主要的 Python 自然语言处理(NLP)库,包括 自然语言工具包(NLTK)、spaCy 和 TensorFlow/Keras。
自然语言理解(NLU)技术受益于一系列非常强大且免费的工具。虽然这些工具非常强大,但没有一个库可以完成所有应用所需的所有 NLP 任务,因此理解不同库的优缺点以及如何将它们结合起来非常重要。
最好地利用这些工具将大大加速任何自然语言理解(NLU)开发项目。这些工具包括 Python 语言本身、开发工具如 JupyterLab,以及许多可以执行多种 NLU 任务的特定自然语言库。 同样重要的是要知道,由于这些工具被许多开发人员广泛使用,像 Stack Overflow(stackoverflow.com/
)这样的活跃在线社区已经发展起来。这些都是解决特定技术问题的绝佳资源。
本章将涵盖以下主题:
-
安装 Python
-
开发软件—JupyterLab 和 GitHub
-
探索这些库
-
查看一个示例
由于有许多在线资源可以使用 Python、JupyterLab 和 GitHub 等工具,因此我们这里只会简要概述它们的使用,以便能够将更多时间集中在 NLP 上。
注意
为了简便起见,我们将演示如何在基础系统中安装这些库。然而,你可能希望在虚拟环境中安装这些库,特别是当你正在进行多个 Python 项目时。以下链接可能有助于安装虚拟环境:packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/
。
技术要求
要运行本章中的示例,你需要以下软件:
-
Python 3
-
pip
或conda
(建议使用pip
) -
JupyterLab
-
NLTK
-
spaCy
-
Keras
接下来的章节将介绍安装这些软件包的过程,建议按照这里列出的顺序安装它们。
安装 Python
设置开发环境的第一步是安装 Python。如果你已经在系统上安装了 Python,可以跳到下一节,但请确保你的 Python 安装包括 Python 3,因为大多数 NLP 库都需要 Python 3。你可以通过在命令行窗口输入以下命令来检查你的 Python 版本,版本号将会显示出来:
$ python --version
注意,如果你同时安装了 Python 2 和 Python 3,你可能需要运行 python3 –version
命令来检查 Python 3 的版本。如果你没有安装 Python 3,你将需要安装它。一些 NLP 库不仅要求 Python 3,还要求 Python 3.7 或更高版本,因此,如果你的 Python 版本低于 3.7,你将需要更新它。
Python 可以在你选择的几乎所有操作系统上运行,包括 Windows、macOS 和 Linux。你可以从 www.python.org
下载适用于你的操作系统的 Python。下载适合操作系统的可执行安装程序并运行。当 Python 安装完成后,你可以通过在命令行或终端中运行上述命令来检查安装情况。你将看到你刚安装的版本,如以下命令行输出所示:
$ python --version
Python 3.8.5
这将安装 Python,但你还需要安装 NLP 的附加库。安装库的操作是通过辅助程序 pip
和 conda
完成的。
pip
和 conda
是两个跨平台工具,可以用来安装 Python 库。在本书中,我们将使用它们来安装几种重要的自然语言处理库和 pip
,但如果你更喜欢使用 conda
作为 Python 管理工具,也是可以的。pip
默认包含在 Python 3.4 及更高版本中,而由于你将需要 3.7 版本来安装 NLP 库,pip
应该已经在你的 Python 环境中可用。你可以使用以下命令检查版本:
$ pip --version
你应该看到以下输出:
$ pip 21.3.1 from c:\<installation dir>\pip (python 3.9)
在接下来的章节中,我们将讨论我们将使用的开发环境:JupyterLab。
开发软件 – JupyterLab 和 GitHub
开发环境对开发过程的效率至关重要。在这一节中,我们将讨论两个流行的开发资源:JupyterLab 和 GitHub。如果你熟悉其他 Python 交互式开发环境(IDE),你可以继续使用你熟悉的工具。然而,本书中的示例将在 JupyterLab 环境中展示。
JupyterLab
JupyterLab 是一个跨平台的编码环境,使得你可以在无需大量设置时间的情况下,轻松地实验不同的工具和技术。它在浏览器环境中运行,但不需要云服务器——本地服务器就足够了。
安装 JupyterLab 可以通过以下 pip
命令完成:
$ pip install jupyterlab
一旦安装了 JupyterLab,你可以使用以下命令运行它:
$ jupyter lab
该命令应在你希望存放代码的目录中的命令行中运行。该命令将启动一个本地服务器,并且 Jupyter 环境将在浏览器窗口中出现,如 图 4.1 所示:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_04_01.jpg
图 4.1 – JupyterLab 启动时的用户界面
图 4.1 中显示的环境包括三种内容,如下所示:
-
笔记本—包含你的编程项目
-
控制台—让你可以直接在 Jupyter 笔记本中访问命令行或终端功能
-
start
命令已运行
当你点击Python 3图标下的Notebook时,你将得到一个新的笔记本,显示一个代码单元,你就可以开始用 Python 编写代码。我们将在本章稍后的查看示例部分返回到 JupyterLab 环境,并开始用 Python 编程,第五章中也会有相关内容。
GitHub
你们中的许多人可能已经熟悉 GitHub,这是一个流行的开源代码仓库系统(github.com
)。GitHub 提供了非常广泛的功能,用于存储和共享代码、开发代码分支以及文档化代码。GitHub 的核心功能目前是免费的。
本书中使用的代码示例可以在github.com/PacktPublishing/Natural-Language-Understanding-with-Python
找到。
下一步是学习几个重要的库,包括我们将在接下来的章节中广泛使用的 NLTK、spaCy 和 Keras。
探索库
在本节中,我们将回顾几个在自然语言处理(NLP)中使用的主要 Python 库;具体来说是 NLTK、spaCy 和 Keras。这些都是非常有用的库,能够执行大多数基础的 NLP 任务。然而,随着你在 NLP 领域经验的积累,你还会发现一些额外的 NLP 库,可能适用于特定任务,鼓励你去探索这些库。
使用 NLTK
NLTK(www.nltk.org/
)是一个非常流行的开源 Python 库,它通过提供对许多常见任务的支持,极大地减少了开发自然语言应用程序的工作量。NLTK 还包括许多语料库(即一套可以直接使用的自然语言文本),这些语料库可以用于探索 NLP 问题和测试算法。
在本节中,我们将介绍 NLTK 的功能,并讨论 NLTK 的安装过程。
正如我们在第三章中讨论的那样,在自然语言理解(NLU)管道中可以执行许多不同的任务,处理从原始单词到最终确定文档含义的过程。NLTK 可以执行其中许多任务。这些功能大多数本身并不会直接提供有用的结果,但它们可以作为管道的一部分,提供很大的帮助。
在几乎所有自然语言项目中,一些基本任务可以轻松通过 NLTK 完成。例如,待处理的文本需要在处理前被拆分成单词。我们可以使用 NLTK 的word_tokenize
函数来实现这一点,如下所示的代码片段所示:
import nltk
import string
from nltk import word_tokenize
text = "we'd like to book a flight from boston to London"
tokenized_text = word_tokenize(text)
print(tokenized_text)
结果将是一个单词数组:
['we',
"'d",
'like',
'to',
'book',
'a',
'flight',
'from',
'boston',
'to',
'London']
请注意,单词we'd
被分为两个部分,we
和'd
,因为它是一个缩写,实际上代表了两个词:we和would。
NLTK 还提供了一些用于基本统计的函数,比如计算文本中单词频率。例如,从我们刚才看到的文本 我们想要预定从波士顿到伦敦的航班 开始,我们可以使用 NLTK 的 FreqDist()
函数来计算每个单词出现的频率:
from nltk.probability import FreqDist
FreqDist(tokenized_text)
FreqDist({'to': 2, 'we': 1, "'d": 1, 'like': 1, 'book': 1, 'a': 1, 'flight': 1, 'from': 1, 'boston': 1, 'london': 1})
在这个例子中,我们从 NLTK 的 probability
包中导入了 FreqDist()
函数,并用它来统计文本中每个单词的频率。结果是一个 Python 字典,其中键是单词,值是单词出现的次数。单词 to
出现了两次,其他每个单词出现了一次。对于如此简短的文本,频率分布并没有特别的启示性,但在查看更大量数据时,它会非常有用。我们将在本章稍后的 查看示例 部分看到一个大语料库的频率分布。
NLTK 还可以执行 nltk.pos_tag(tokenized_text)
函数来进行词性标注:
nltk.pos_tag(tokenized_text)
[('we', 'PRP'),
("'d", 'MD'),
('like', 'VB'),
('to', 'TO'),
('book', 'NN'),
('a', 'DT'),
('flight', 'NN'),
('from', 'IN'),
('boston', 'NN'),
('to', 'TO'),
('london', 'VB')]
类似地,NLTK 提供了用于解析文本的函数。回想一下,第三章讨论了解析。正如第一章中所讨论的,NLTK 还提供了创建和应用 正则 表达式 (regexes) 的函数。
这些是 NLTK 最有用的功能之一。NLTK 的完整功能集合过于庞大,无法在这里列出,但我们将在 第六章 和 第八章 中回顾这些其他功能。
安装 NLTK
NLTK 需要 Python 3.7 或更高版本。在 Windows 上的安装过程是运行以下命令:
$ pip install nltk
对于 Mac 或 Unix 环境,在终端窗口中运行以下命令:
$ pip install --user -U nltk
在下一节中,我们将介绍另一个流行的 NLU 库,spaCy,并解释它能做什么。与 NLTK 一样,我们将在后续章节中广泛使用 spaCy。
使用 spaCy
spaCy 是另一个非常流行的包,可以执行与 NLTK 相似的许多 NLP 任务。两个工具包都非常强大。spaCy 通常更快,因此更适合用于已部署的应用程序。两个工具包都支持多种语言,但并非所有 NLU 任务都支持所有语言,因此在选择 NLTK 和 spaCy 时,考虑特定应用的语言需求非常重要。
与 NLTK 一样,spaCy 也可以执行许多基本的文本处理功能。让我们来看看吧!
在 spaCy 中设置分词的代码与 NLTK 中的代码非常相似,只有函数名称略有不同。结果是一个包含单词的数组,每个元素都是一个标记。请注意,nlp
对象是使用 en_core_web_sm
模型初始化的,该模型告诉它使用特定网页数据集的统计信息,en_core_web_sm
:
import spacy
from spacy.lang.en import English
nlp = spacy.load('en_core_web_sm')
text = "we'd like to book a flight from boston to london"
doc = nlp(text)
print ([token.text for token in doc])
['we', "'d", 'like', 'to', 'book', 'a', 'flight', 'from', 'boston', 'to', 'london']
我们还可以计算文本中单词出现频率等统计数据:
from collections import Counter
word_freq = Counter(words)
print(word_freq)
Counter({'to': 2, 'we': 1, "'d": 1, 'like': 1, 'book': 1, 'a': 1, 'flight': 1, 'from': 1, 'boston': 1, 'london': 1})
spaCy 和 NLTK 之间唯一的区别是,NLTK 使用 FreqDist
函数,而 spaCy 使用 Counter
函数。结果——一个 Python 字典,单词作为键,频率作为值——在这两个库中是相同的。
和 NLTK 一样,我们也可以使用 spaCy 执行词性标注:
for token in doc:
print(token.text, token.pos_)
这将产生以下的词性标注结果:
we PRON
'd AUX
like VERB
to PART
book VERB
a DET
flight NOUN
from ADP
boston PROPN
to ADP
london PROPN
不幸的是,NLTK 和 spaCy 使用不同的标签来表示不同的词性。这不一定是一个问题,因为即使对于同一种语言,也没有正确的或标准的词性集合。然而,在一个应用程序中,词性的一致性是非常重要的,所以开发者需要意识到这种差异,并确保不要混淆 NLTK 和 spaCy 的词性。
spaCy 还有另一个非常有用的功能,那就是命名实体识别(NER)。NER 是识别文本中提到的特定人物、组织、地点或其他实体的任务。NER 可以作为一个独立的任务,也可以是另一个任务的一部分。例如,一家公司可能会对自己产品在 Facebook 上的提及感兴趣,那么他们只需要进行产品的 NER。另一方面,如果一家公司想知道他们的产品是以积极还是消极的方式被提及,他们就需要同时执行 NER 和情感分析(SA)。
大多数 NLP 库都可以执行命名实体识别(NER);然而,在 spaCy 中特别容易做到。给定一个文档,我们只需要请求使用 ent
样式渲染文档,如下所示:
import spacy
nlp = spacy.load("en_core_web_sm")
text = "we'd like to book a flight from boston to new york"
doc = nlp(text)
displacy.render(doc,style='ent',jupyter=True,options={'distance':200})
渲染结果显示,boston
和 new york
这两个命名实体被赋予了地理政治实体(GPE)标签,如 图 4.2 所示:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_04_02.jpg
图 4.2 – 对于“我们想预订从波士顿到纽约的航班”的命名实体识别(NER)
解析或分析句子中单词之间的句法关系非常容易,只需将 style
参数的值从 ent
改为 dep
,几乎可以使用相同的代码。稍后我们将在 图 4.6 中看到一个句法解析的示例:
nlp = spacy.load('en_core_web_sm')
doc = nlp('they get in an accident')
displacy.render(doc,style='dep',jupyter=True,options={'distance':200})
安装 spaCy 可以通过以下 pip
命令完成:
$ pip install -U spacy
接下来我们要看的库是 Keras ML 库。
使用 Keras
Keras (keras.io/
) 是另一个流行的 Python NLP 库。Keras 比 NLTK 或 spaCy 更加专注于机器学习(ML),并将在本书中作为 NLP 深度学习(DL)应用的首选库。它建立在另一个名为 TensorFlow (www.tensorflow.org/
) 的包之上,TensorFlow 是由 Google 开发的。由于 Keras 是基于 TensorFlow 构建的,因此可以在 Keras 中使用 TensorFlow 的函数。
由于 Keras 专注于机器学习(ML),它在文本预处理方面的功能有限。例如,与 NLTK 或 spaCy 不同,它不直接支持词性标注(POS tagging)或句法分析(parsing)。如果需要这些功能,最好使用 NLTK 或 spaCy 来进行文本预处理。Keras 支持分词和去除多余的标记,例如标点符号和 HTML 标记。
Keras 特别适用于使用神经网络(NN)的文本处理应用。这将在 第十章 中详细讨论。尽管 Keras 包含的高阶功能较少,不能一步完成像词性标注(POS tagging)或句法分析(parsing)这样的 NLP 功能,但它确实提供了从数据集训练词性标注器并将其部署到应用中的能力。
由于 Keras 已包含在 TensorFlow 中,安装 TensorFlow 时会自动安装 Keras。因此,不需要额外安装 Keras。只需执行以下命令即可:
$ pip install tensorflow
了解其他 NLP 库
还有不少其他 Python 库也包括 NLP 功能,并且在某些情况下非常有用。这些库包括 PyTorch(pytorch.org/
),它基于深度神经网络(DNN)进行处理;scikit-learn(scikit-learn.org/stable/
),它包含一般的机器学习(ML)功能;以及 Gensim(radimrehurek.com/gensim/
),用于主题建模等等。然而,我建议你首先使用我们这里介绍的基本包来做几个项目,直到你对 NLP 更加熟悉。如果以后你有对额外功能、不同语言或比基本包更快的处理速度的需求,再去探索这些其他的包。
在下一个话题中,我们将讨论如何在 NLP 库中进行选择。值得记住的是,选择库并不是一个“非此即彼”的过程——如果一个库有其他库没有的优点,可以轻松地将不同的库混合使用。
在 NLP 库中进行选择
前面讨论的库都非常有用且强大。在某些情况下,它们的功能有所重叠。这就提出了一个问题:如何在特定应用中选择使用哪些库。尽管所有这些库都可以在同一个应用中组合使用,但如果使用较少的库,可以降低应用的复杂性。
NLTK 在语料库统计和基于规则的语言学预处理中非常强大。例如,一些有用的语料库统计包括计数单词、计数词性、计数词对(bigrams),以及列出上下文中的单词(concordances)。spaCy 速度很快,其 displaCy 可视化库对于了解处理结果非常有帮助。Keras 在深度学习(DL)方面非常强大。
在项目的生命周期中,通常有必要从一些工具开始,帮助你快速获得数据的整体概览,例如 NLTK 和 spaCy。这一初步分析将有助于选择需要的工具,以进行全面的处理和部署。由于使用 Keras 等工具训练深度学习模型可能非常耗时,因此使用更传统的方法进行一些初步调查将有助于缩小需要进一步调查的范围,从而选择合适的深度学习方法。
了解其他对 NLP 有用的包
除了直接支持自然语言处理(NLP)的包外,还有许多其他有用的通用开源 Python 包,提供了用于一般数据管理的工具,包括自然语言数据。这些包包括以下内容:
-
NumPy: NumPy(
numpy.org/
)是一个强大的包,包含许多用于数值计算的函数,我们将在第九章、第十章、第十一章和第十二章中使用这些函数 -
pandas: pandas(
pandas.pydata.org/
)提供了用于数据分析和处理的一般工具,包括自然语言数据,特别是表格形式的数据 -
scikit-learn: scikit-learn 是一个强大的机器学习包,包括文本处理功能(
scikit-learn.org/stable/
)
还有几个可视化包,对于数据的图形表示和处理结果非常有帮助。可视化在 NLP 开发中非常重要,因为它通常能比数字表格提供更易理解的结果表示。例如,可视化可以帮助你发现趋势、定位错误并比较实验条件。我们将在全书中使用可视化工具,尤其是在第六章中。可视化工具包括用于表示不同类型数字结果的通用工具,无论这些结果是否与 NLP 相关,也包括专门设计用于表示自然语言信息(如句法分析和命名实体识别结果)的工具。可视化工具包括以下内容:
-
Matplotlib: Matplotlib(
matplotlib.org/
)是一个流行的 Python 可视化库,尤其擅长创建数据图表,包括 NLP 数据。如果你尝试比较使用几种不同技术处理的结果,绘制结果图表通常可以迅速提供有关这些技术效果的洞察,这对评估非常有帮助。我们将在第十三章中再次讨论评估主题。 -
Seaborn:Seaborn(
seaborn.pydata.org/
)基于 Matplotlib,能够帮助开发者绘制出代表统计信息的美观图表。 -
displaCy:displaCy 是 spaCy 工具的一部分,特别擅长表示自然语言结果,如词性标注、句法分析和命名实体,这些我们在第三章中讨论过。
-
WordCloud:WordCloud(
amueller.github.io/word_cloud/
)是一个专门用于可视化语料库中单词频率的库,当单词频率很重要时非常有用。我们将在下一部分看到一个词云的示例。
到目前为止,我们已经回顾了软件开发环境的技术要求以及我们将要使用的 NLP 库。在接下来的部分,我们将通过一个示例将所有内容结合起来。
查看一个示例
为了说明这些概念,我们将在 JupyterLab 中做一个示例,探索电影评论的情感分析(SA)任务。我们将看看如何应用 NLTK 和 spaCy 包来了解数据的特征,这将帮助我们规划后续的处理步骤。
我们将要查看的数据集是一个流行的 2,000 条电影评论集,按评论者是否表达了对电影的积极或消极情感进行分类(www.cs.cornell.edu/people/pabo/movie-review-data/
)。
数据集引用
Bo Pang 和 Lillian Lee,Seeing stars: Exploiting class relationships for sentiment categorization with respect to rating scales, Proceedings of the ACL, 2005。
这是情感分析(SA)任务的一个很好的示例,我们在第一章中已经介绍过。
设置 JupyterLab
我们将使用 JupyterLab,所以让我们启动它。正如我们之前看到的,你可以通过在命令(Windows)或终端(Mac)窗口中输入以下命令来启动 JupyterLab:
$ jupyter lab
这将启动一个本地 Web 服务器,并在 Web 浏览器中打开 JupyterLab 窗口。在 JupyterLab 窗口中,通过选择文件 | 新建 | 笔记本来打开一个新的笔记本,随后会出现一个未命名的笔记本(你可以随时通过选择文件 | 重命名笔记本来更改其名称)。
我们将从导入我们将在这个示例中使用的库开始,如下所示。我们将使用 NLTK 和 spaCy 的 NLP 库,以及一些用于数值运算和可视化的通用库。随着示例的展开,我们将看到这些库的使用方法:
# NLP imports
import nltk
import spacy
from spacy import displacy
# general numerical and visualization imports
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from collections import Counter
import numpy as np
在 JupyterLab 单元格中输入上述代码并运行。运行此单元格(运行 | 运行选定单元格)将导入库,并为你创建一个新的代码单元格。
通过在新的代码单元格中输入nltk.download()
来下载电影评论数据。这将打开一个新的NLTK 下载器窗口,如图 4.3所示:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_04_03.jpg
图 4.3 – NLTK 下载窗口
在movie_reviews
上。点击下载按钮下载语料库。如果你想改变数据下载的路径,可以选择文件 | 更改下载目录。点击文件 | 退出退出下载窗口并返回到 JupyterLab 界面。
如果你查看你下载数据的目录,你会看到两个文件夹:neg
和pos
。这些文件夹分别包含负面和正面评论。这代表了评论的标注,即人工标注员对于评论是正面还是负面的判断。这种目录结构是文本分类标注的常见方式,你将在许多数据集中看到它。movie_reviews
文件夹中的README
文件解释了标注的具体细节。
如果你查看语料库中的一些电影评论,你会发现,文本的正确标注并不总是显而易见的。
下一个代码块显示了导入评论并打印语料库中的一个句子:
#import the training data
from nltk.corpus import movie_reviews
sents = movie_reviews.sents()
print(sents)
[['plot', ':', 'two', 'teen', 'couples', 'go', 'to', 'a', 'church', 'party', ',', 'drink', 'and', 'then', 'drive', '.'], ['they', 'get', 'into', 'an', 'accident', '.'], ...]
In [5]:
sample = sents[9]
print(sample)
['they', 'seem', 'to', 'have', 'taken', 'this', 'pretty', 'neat', 'concept', ',', 'but', 'executed', 'it', 'terribly', '.']
由于movie_reviews
是一个 NLTK 语料库,提供了多种语料库方法,包括将句子列出为单独的句子数组。我们还可以按编号选择语料库中的单个句子,如前面的代码块所示,我们选择并打印了语料库中的第九个句子。
你可以看到句子已经被分词,或者说被拆分成了单个单词(包括标点符号)。这是几乎所有自然语言处理应用中的重要准备步骤。
处理一个句子
现在,让我们对这个样本文本进行实际的自然语言处理。我们将使用 spaCy 库进行词性标注和基于规则的解析,然后使用 displaCy 库可视化结果。
我们首先需要创建一个基于网页数据的nlp
对象,en_core_web_sm
,它是一个基本的小型英语模型。虽然也有更大的模型可用,但它们加载速度较慢,因此为了简便起见,我们在这里使用小型模型。接着,我们使用nlp
对象识别词性并解析这个句子,如以下代码块所示:
nlp = spacy.load('en_core_web_sm')
doc = nlp('they get in an accident')
displacy.render(doc,style='dep',jupyter=True,options={'distance':200})
在displacy.render
命令中,我们请求了一个依赖解析(styles='dep'
)。这是一种我们将在第八章中详细探讨的分析方法。目前,简单来说,它是展示句子中各单词之间关系的常见方法。最终的依赖解析如图 4.4所示:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_04_04.jpg
图 4.4 – “他们发生了事故”的依赖解析
现在我们已经加载了语料库并查看了其中的一些句子示例,接下来我们将查看语料库的一些整体属性。
查看语料库属性
虽然语料库有许多属性,但一些最有趣且富有洞察力的属性是单词频率和词性频率,我们将在接下来的两节中回顾这些内容。不幸的是,由于篇幅限制,我们无法详细探讨其他语料库属性,但查看单词和词性频率应该能帮助你入门。
单词频率
在本节中,我们将查看整个语料库的一些属性。例如,我们可以使用以下代码查看最频繁的单词:
words = movie_reviews.words()
word_counts = nltk.FreqDist(word.lower() for word in words if word.isalpha())
top_words = word_counts.most_common(25)
all_fdist = pd.Series(dict(top_words))
# Setting fig and ax into variables
fig, ax = plt.subplots(figsize=(10,10))
# Plot with Seaborn plotting tools
plt.xticks(rotation = 70)
plt.title("Frequency -- Top 25 Words in the Movie Review Corpus", fontsize = 30)
plt.xlabel("Words", fontsize = 30)
plt.ylabel("Frequency", fontsize = 30)
all_plot = sns.barplot(x = all_fdist.index, y = all_fdist.values, ax=ax)
plt.xticks(rotation=60)
plt.show()
如前面的代码所示,我们首先通过使用语料库对象的words()
方法来收集movie_review
语料库中的单词。然后,我们使用 NLTK 的FreqDist()
函数来统计单词的频率。与此同时,我们将单词转换为小写,并忽略掉数字和标点符号等非字母单词。接着,为了让可视化更清晰,我们将查看的单词限制为最频繁的 25 个单词。你可能会对在代码块中尝试不同的top_words
值感兴趣,以查看图表在更多或更少单词情况下的效果。
当我们调用plt.show()
时,单词频率分布会被显示出来。这可以在图 4**.5中看到:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_04_05.jpg
图 4.5 – 可视化电影评论语料库中的最频繁单词
正如图 4**.5所示,最频繁出现的单词毫无意外是the,其出现频率约是第二常见单词a的两倍。
另一种也可能有帮助的单词频率可视化方法是all_fdist
,并使用 Matplotlib 进行显示:
from wordcloud import WordCloud
wordcloud = WordCloud(background_color = 'white',
max_words = 25,
relative_scaling = 0,
width = 600,height = 300,
max_font_size = 150,
colormap = 'Dark2',
min_font_size = 10).generate_from_frequencies(all_fdist)
# Display the generated image:
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis("off")
plt.show()
结果的词云展示在图 4**.6中。我们可以看到,像the和a这样非常频繁的单词,相较于其他单词,显示得非常大:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_04_06.jpg
图 4.6 – 电影评论语料库中前 25 个单词的词云
请注意,几乎所有频繁出现的单词都是在大多数英语文本中常用的词汇。唯一的例外是film,这在电影评论语料库中是可以预料到的。由于这些频繁出现的单词出现在大多数文本中,它们的出现不会帮助我们区分不同类型的文本。如果我们处理的是情感分析(SA)等分类问题,我们应该考虑在尝试对该语料库进行情感分析分类器训练之前,从文本中去除这些常见单词。这些单词被称为停用词,它们的移除是常见的预处理步骤。我们将在*第五章**.*中详细讨论停用词移除。
词性频率
我们还可以使用以下代码查看最常见的词性。为了减少图表的复杂性,我们将显示限制为 18 个最常见的词性。标注完单词之后,我们会遍历句子,统计每个标签的出现次数。然后,标签列表会按出现频率从高到低排序。
NLTK POS 标注代码中使用的词性标签是广泛使用的 Penn Treebank 词性标签,文档可以参考www.cs.upc.edu/~nlp/SVMTool/PennTreebank.html
。这个标签集总共有 36 个标签。之前的自然语言处理研究发现,传统的英语词性(名词、动词、形容词、副词、连词、感叹词、代词和介词)对于计算目的来说不够精细,因此通常会添加额外的词性标签。例如,不同形式的动词,如walk、walks、walked 和 walking,通常会被分配不同的词性。例如,walk 会被分配为 VB ——即动词原形——而 walks 则会被分配为 VBZ ——即动词第三人称单数现在时——词性。传统上,这些都被称为动词。
首先,我们会从语料库中提取句子,并对每个单词进行词性标注。重要的是,要对整个句子进行词性标注,而不仅仅是单独的单词,因为许多单词有多种词性,而分配给单词的词性取决于它所在句子的其他单词。例如,book 在 book a flight 这个句子开头时可以被识别并标注为动词,而在 I read the book 中,book 则可以被标注为名词。在以下代码中,我们展示了该语料库中词性的频率:
movie_reviews_sentences = movie_reviews.sents()
tagged_sentences = nltk.pos_tag_sents(movie_reviews_sentences)
total_counts = {}
for sentence in tagged_sentences:
counts = Counter(tag for word,tag in sentence)
total_counts = Counter(total_counts) + Counter(counts)
sorted_tag_list = sorted(total_counts.items(), key = lambda x: x[1],reverse = True)
all_tags = pd.DataFrame(sorted_tag_list)
most_common_tags = all_tags.head(18)
# Setting figure and ax into variables
fig, ax = plt.subplots(figsize=(15,15))
all_plot = sns.barplot(x = most_common_tags[0], y = most_common_tags[1], ax = ax)
plt.xticks(rotation = 70)
plt.title("Part of Speech Frequency in Movie Review Corpus", fontsize = 30)
plt.xlabel("Part of Speech", fontsize = 30)
plt.ylabel("Frequency", fontsize = 30)
plt.show()
在电影评论语料库中,我们可以看到,最常见的标签是 NN 或 普通名词,其次是 IN 或 介词或并列连词,以及 DT 或 限定词。
结果,再次使用 Matplotlib 和 Seaborn 库,通过图形展示在图 4.7中:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_04_07.jpg
图 4.7 – 可视化电影评论语料库中最常见的词性
我们可以查看其他文本属性,比如文本长度的分布,比较正面和负面评论的属性,看是否能找到一些区分这两类评论的特征。正面和负面评论的平均长度是否不同?它们的词性分布有差异吗?如果我们注意到一些差异,那么我们可以在分类新的评论时加以利用。
总结
在本章中,我们介绍了 NLP 应用开发中使用的主要开发工具和 Python 库。我们讨论了 JupyterLab 开发环境和 GitHub 软件仓库系统。我们介绍的主要库有 NLTK、spaCy 和 Keras。虽然这不是一个详尽无遗的 NLP 库列表,但足以启动几乎任何 NLP 项目。
我们介绍了主要库的安装和基本使用,并提供了一些选择库的建议技巧。我们总结了一些有用的辅助包,并以一个简单的示例结束,展示了这些库如何用于执行一些 NLP 任务。
本章讨论的内容使你对最有用的 Python 包在 NLP 中的应用有了基本了解,这些包将在本书的其余部分中使用。此外,本章的讨论也帮助你开始理解如何为未来的项目选择工具的原则。我们已经实现了帮助你设置自然语言处理工具的目标,并通过使用 NLTK 和 spaCy 进行简单文本处理以及使用 Matplotlib 和 Seaborn 进行可视化来进行说明。
在下一章,我们将讨论如何识别和准备数据,以便使用 NLP 技术进行处理。我们将讨论来自数据库、网络和其他文档的数据,以及隐私和伦理考虑。对于没有自己数据的读者或希望将结果与其他研究人员的结果进行比较的读者,本章还将讨论一些通用的语料库。接着,我们将讨论一些预处理步骤,如分词、词干提取、去除停用词和词形还原。
第五章:自然语言数据 – 查找和准备数据
本章将教你如何识别并准备适用于自然语言理解技术的数据处理。它将讨论来自数据库、网络以及不同种类文档的数据,还会涉及隐私和伦理考虑。我们将简要介绍“奥兹巫师”技术。如果你没有自己的数据,或者希望将自己的结果与其他研究者的结果进行对比,本章还将讨论一些通用可用且常用的语料库。接着,我们将讨论诸如词干提取和词形还原等预处理步骤。
本章将涵盖以下主题:
-
数据来源与标注
-
确保隐私并遵循伦理考虑
-
通用可用的语料库
-
预处理数据
-
针对特定应用的预处理类型
-
在预处理技术中进行选择
查找数据来源并进行注释
数据是所有自然语言处理(NLP)项目的起点。数据可以是书面文本或转录的语音。数据的目的是教会 NLP 系统在未来遇到类似数据时应该做什么。特定的数据集也被称为语料库或数据集,我们通常会交替使用这些术语。最近,已经开发出了大型的预训练模型,它们大大减少了许多应用中对数据的需求。然而,这些预训练模型(将在第十一章中详细讨论)在大多数情况下并不会消除对特定应用数据的需求。
书面语言数据可以有任何长度,从非常短的文本(如推文)到多页文档甚至书籍。书面语言可以是互动性的,例如用户与系统之间的聊天记录;也可以是非互动性的,如新闻文章或博客。类似地,口语数据可以长也可以短。与书面语言一样,它可以是互动性的,如两人对话的转录,也可以是非互动性的,如广播新闻。所有 NLP 数据的共同点是它是语言,由一个或多个自然语言的词汇组成,用于人们之间的交流。每个 NLP 项目的目标是将这些数据进行处理,使用特定算法获取关于数据创作者意图的信息。
任何 NLP 项目的第一步之一是找到合适的数据。为此,你需要考虑你进行该项目的目标。
查找适用于自己应用的数据
如果你有一个特定的实际应用想要构建,通常很容易知道你需要什么样的数据。例如,要构建一个企业助手(如图 1.3中显示的交互式应用之一),你需要用户与人类代理或你想要构建的交互系统之间对话的示例。这些示例可能已经存在,形式可能是现有的呼叫中心记录。
我们在接下来的子章节中将考虑以下示例:
-
呼叫中心对话
-
聊天记录
-
数据库
-
信息板和客户评价
让我们开始吧!
呼叫中心对话
如果你计划构建一个执行客户支持的语音助手,在许多情况下,目标是将一些工作从现有的呼叫中心转移到语音助手上。在这种情况下,通常会有很多之前人类客服代表与客户之间通话的转录文本,这些文本可以作为训练应用程序的数据。客户的问题将作为应用程序需要理解的示例,而客服代表的回答将作为系统应如何回应的示例。在这过程中,需要有一个标注步骤,为每个客户的发言分配一个总体意图或客户目标。大多数时候,标注过程还需要标记发言中的实体。在开始标注意图和实体之前,应该有一个初步设计步骤,确定意图和实体。
一旦数据被标注,它就可以作为应用程序的训练数据。训练过程将根据使用的技术有所不同。我们将在第九章和第十章中详细讨论数据在训练中的应用。
聊天记录
如果你有一个包含聊天窗口的网站,客户输入的问题就可以作为训练数据,就像呼叫中心对话的转录本一样。数据之间的唯一区别是,呼叫中心的数据是基于语音的,而不是输入的文字。否则,标注、设计和训练过程将非常相似。数据本身会有一些不同,因为输入的文字通常比语音输入短,并且可能包含拼写错误。
数据库
数据库通常是企业数据的一个很好的来源。数据库中经常包含自由文本字段,用户可以在其中输入任何信息。自由文本字段用于诸如事件报告的叙述摘要等信息,并且通常包含其他数据库字段中未捕获的丰富信息。自然语言处理(NLP)在从这些丰富的信息中学习方面非常有价值,因为自由文本字段的内容可以通过 NLP 技术进行分类和分析。这种分析可以为数据库主题提供更多的洞见。
信息板和客户评价
像自由文本字段一样,留言板和客户支持论坛包含了来自客户的未格式化输入。客户支持留言板和客户产品评论可以成为有关产品故障以及客户对产品态度的宝贵数据来源。尽管这些信息可以由人工分析,但人工分析既费时又昂贵。在许多情况下,这些信息非常丰富,可以作为非常有用的 NLP 应用的基础。
到目前为止,我们已经讨论了特定应用的数据以及如何为该应用的目的找到并分析这些数据。另一方面,有时你可能会对分析数据作为研究项目的一部分感兴趣。下一部分将讨论你可以从哪里获得研究项目的数据。
寻找研究项目的数据
如果你的目标是为 NLP 科学做出贡献,或者如果你只是希望能够将自己的算法与其他研究者的工作进行比较,那么你所需要的数据将与之前讨论的数据大不相同。与其寻找没人使用过的数据(可能是你企业内部的专有数据),你更希望使用那些其他研究人员可以自由访问的数据。理想情况下,这些数据应该是公开的,但如果不是,重要的是你要将其提供给 NLP 研究社区中的其他人,以便他们能够复现你的工作。科学会议或期刊几乎总是要求任何新收集的数据在论文展示或发布之前必须公开。接下来我们将讨论几种收集新数据的方法。
收集数据
尽管有很多现成的数据来源,但有时你可能无法从现有资源中找到完全符合需求的数据。也许你想处理一个非常具体的技术话题,或者你对一个快速变化的话题感兴趣,比如 COVID-19。你可能需要特定于某个地区的数据,或是某些季节性的数据,这些数据只适用于一年中的特定时段。由于这些原因,你可能需要专门为你的项目收集数据。
在这些情况下,有几种很好的方法可以收集数据,包括应用程序编程接口(API)、众包数据和“奥兹巫师”方法。我们将在接下来的部分中回顾这些方法。
API
一些社交媒体服务提供可以通过 API 访问的动态信息。例如,Twitter 提供了一个 API,开发者可以用它访问 Twitter 服务(developer.twitter.com/en/docs/twitter-api
)。
众包数据
一些数据可以通过像亚马逊的机械土耳其人平台(www.mturk.com/
)这样的工具由人工工人生成。需要生成的数据必须清楚地描述给众包工作者,并包括任何关于数据生成的参数或约束条件。对于普通人容易理解的数据,而不是技术性或专业的科学数据,尤其适合用于众包。众包可以是获取数据的有效方式;然而,为了使这些数据有用,必须采取一些预防措施:
-
确保众包工作者有足够的指示,以确保他们创建的数据与系统在部署过程中将遇到的真实数据足够相似,这是非常重要的。必须监控众包工作者的数据,以确保他们正确遵循指示。
-
众包工作者必须具备适当的知识,以便为专业应用生成合适的数据。例如,如果众包工作者需要生成医学报告,他们必须具备医学背景。
-
众包工作者必须具备足够的语言知识,以确保他们生成的数据能够代表真实数据。这些数据不必完全符合语法规范——部署过程中遇到的语言,尤其是语音数据,并不一定完美。过分坚持语法规范可能导致数据过于生硬、不现实。
奥兹巫师法
奥兹巫师法(WoZ)是一种数据收集方法,其基本原理是设置一种计算机与人类互动的情境,系统看似在处理用户的输入,实际上,处理工作是由幕后的人类完成的。奥兹巫师这一名称源于电影中的一句台词:“不要注意幕布后的那个人”,实际上那个人在控制一个本应是巫师的投影。该技术背后的理念是,如果用户认为系统在处理数据,那么他们的行为将反映出他们在与实际系统互动时的行为。虽然 WoZ 方法可以提供高质量的数据,但它成本较高,因为设置必须小心安排,以确保实验对象没有意识到他们正在与自动化系统互动。你可以在en.wikipedia.org/wiki/Wizard_of_Oz_experiment
了解关于 WoZ 范式的详细信息,更多关于进行 WoZ 实验的信息请参考:www.answerlab.com/insights/wizard-of-oz-testing
。
在数据收集过程中,我们不仅关注语言本身,还关注描述数据的附加信息,或者说是元数据。下一节将介绍元数据的基本概念,然后继续讨论一种非常重要的元数据类型——注释。
元数据
数据集通常包括元数据。元数据指的是关于数据的信息,而不是数据本身。几乎任何数据提供者认为可能对后续处理有用的信息都可以作为元数据包含在内。一些最常见的元数据类型包括数据的自然语言、口语数据的讲者、发言时间和地点,以及书面数据的作者。如果口语数据是通过语音识别过程获得的,语音识别器的置信度通常会作为元数据包含。接下来的部分将介绍注释,这是可能是最重要的一种元数据类型。
注释
最重要的元数据类型之一是文本的预期自然语言处理结果,或称为注释。
在大多数情况下,新收集的数据需要进行注释,除非要进行的实验涉及无监督学习(关于无监督学习的更多内容,请参考第十二章)。注释是将输入与训练系统预期生成的自然语言处理结果相关联的过程。系统通过处理带注释的示例来学习如何分析数据,然后将这种学习应用于新的、没有注释的示例。
由于注释实际上是监督学习中的监督,因此用于无监督学习实验的数据不需要带有预期的自然语言处理结果的注释。
有几种软件工具可以用于注释自然语言处理文本数据。例如,文本工程通用架构(GATE)(gate.ac.uk/
)包括一个经过充分测试的用户界面,使得注释者可以为文档及其部分赋予意义。
在接下来的部分中,我们将“了解”语音数据的转录以及标注者之间一致性的问题。
转录
转录,即将音频文件中的语音转换为书面形式,是语音数据的重要标注步骤。如果语音中没有显著的噪声,商业自动语音识别(ASR)系统,如 Nuance Dragon(www.nuance.com/dragon/business-solutions/dragon-professional-individual.html
),可以提供相当准确的音频文件初步转录结果。如果你使用商业 ASR 进行转录,结果仍然需要由研究人员审查,以便捕捉并纠正 ASR 系统可能出现的错误。另一方面,如果语音非常嘈杂或安静,或者包含几个人同时交谈的内容,商业 ASR 系统可能会出现太多错误,导致自动转录结果不具有参考价值。在这种情况下,可以使用手动转录软件,如 TranscriberAG(transag.sourceforge.net/
)。你需要记住,转录嘈杂或其他问题语音的手动过程可能会非常缓慢,因为转录员必须先理解语音内容才能进行转录。
标注者一致性
标注者对于任何给定数据项的正确标注并不总是达成一致。特别是当标注说明不清晰时,关于正确标注的意见可能会有较大差异。此外,标注者可能没有仔细思考标注的具体要求,或者标注者需要标注的数据可能本身就带有主观性。基于这些原因,同一数据项的标注通常由多个标注者完成,尤其是当数据具有主观性时。例如,标注与文本或语音相关的情感,就是一种具有高度分歧潜力的数据。标注者之间的同意度被称为标注者一致性,通常通过所谓的卡帕统计量来衡量。卡帕统计量比单纯计算百分比一致性更为优越,因为它考虑了标注者可能仅仅是偶然达成一致的情况。
nltk.metrics.agreement
,可以用来计算标注者一致性。
到目前为止,我们讨论了获取自己数据的过程,但也有许多现成的、已经标注并且可以自由获取的数据集。我们将在下一节中讨论现成的数据。之后我们在实际操作中会直接使用这些现成数据集。
通用可用语料库
获取数据的最简单方法是使用覆盖你所要解决问题类型的现有语料库。使用现有语料库,你不需要收集数据,除非现有的注释不适合你的问题,否则你可能不需要重新注释。任何隐私问题在数据集发布之前都会得到解决。使用现有语料库的一个附加优点是,其他研究人员可能已经发布了描述他们在语料库上的工作论文,你可以将这些与自己的工作进行比较。
幸运的是,存在许多标准的现有数据集,你可以下载并用于几乎任何自然语言处理问题。一些是免费的,其他则需要付费。
许多组织提供现有数据集,例如以下几个:
-
语言数据联盟 (
www.ldc.upenn.edu/
): 提供多种语言的文本和语音数据,并管理捐赠的数据。 -
Hugging Face (
huggingface.co/
): 提供多语言的数据集以及自然语言处理模型。Hugging Face 提供的一些热门数据集包括电影评论、产品评论和 Twitter 情感分类。 -
Kaggle (
www.kaggle.com/
): 提供多个数据集,包括用户贡献的数据集。 -
欧洲语言资源协会(ELRA)(
www.elra.info/en/
): 一个提供多语言数据的欧洲组织。 -
与自然语言处理库(如 NLTK 和 spaCy)一起分发的数据:自然语言处理库包含数十个不同规模和语言的语料库。很多数据都带有注释,支持多种不同类型的应用。
-
政府数据:政府收集大量数据,包括文本数据,这些数据通常是公开的,可以用于研究。
-
Librispeech
www.openslr.org/12
: 一个大型的阅读语音数据集,基于为视力障碍人士朗读的有声书,主要用于语音项目。
到目前为止,我们已经涵盖了获取数据和添加元数据(包括注释)的话题。在数据用于自然语言处理应用之前,我们还需要确保其使用符合伦理。伦理考虑将是下一部分的主题。
确保隐私并遵循伦理考虑
语言数据,尤其是企业内部的数据,可能包含敏感信息。立刻想到的例子有医疗和金融数据。当一个应用涉及这些话题时,它很可能包含有关健康或财务的敏感信息。如果信息与特定人关联,它将变得更加敏感。这种信息被称为个人可识别信息(PII),由美国劳工部定义如下:
“任何可以通过直接或间接手段合理推断出信息适用对象身份的资料表示”(www.dol.gov/general/ppii
)。这是一个广泛且复杂的问题,完整的讨论超出了本书的范围。然而,值得讨论的是一些针对 NLP 应用的关键点,如果你需要处理任何形式的敏感数据,应该考虑这些点。
确保训练数据的隐私
对于一般可用的语料库,数据通常已被处理,以便移除敏感信息。另一方面,如果你处理的是自己获取的数据,你需要考虑如何处理在原始数据中可能遇到的敏感信息。
一种常见的策略是用占位符替换敏感数据,例如<NAME>
、<LOCATION>
和<PHONENUMBER>
。这样可以让训练过程在不暴露任何敏感数据的情况下学习如何处理自然语言。这不应影响训练系统处理自然语言的能力,因为很少有应用程序会根据具体的姓名或地点对语句做出不同的分类。如果分类依赖于比<LOCATION>
更具体的信息,可以使用更具体的占位符,例如城市名或国家名。实际上,在训练中使用占位符是有帮助的,因为它减少了训练模型对训练数据中特定名称过拟合的可能性。
确保运行时数据的隐私
在运行时,当应用程序部署时,进入的数据自然会包含用户为实现目标而输入的敏感数据。通常对通过表单输入的数据(如社会安全号码或信用卡号码)采取的任何预防措施,当然也适用于通过自然语言文本和语音输入的数据。在某些情况下,处理这些数据将受到法规和立法的约束,你需要了解并遵守相关规定。
伦理地对待人类受试者
在实验过程中可以收集自然语言和语音数据,例如在 WoZ 研究中,当人类用户或受试者提供语音和文本进行研究时。大学和其他研究机构有委员会审查所有涉及人类受试者的实验程序,以确保受试者受到伦理对待。例如,受试者必须提供知情同意书,不能受到伤害,必须保护他们的匿名性,避免欺骗行为,并且他们必须能够随时退出研究。如果你在实验环境中收集数据,请确保了解你所在机构关于人类受试者委员会或类似机构审批程序的规则。你可能需要为审批过程预留额外的时间。
公平对待众包工人
如果使用众包工人(例如 Amazon Mechanical Turk 工人)来创建或注释数据,重要的是要记住公平对待他们——最重要的是按时支付公平报酬——还要确保他们拥有完成任务所需的工具,并尊重地听取他们可能对任务提出的任何疑虑或问题。
现在我们已经确定了数据来源并讨论了伦理问题,让我们继续讨论如何准备数据以便在应用程序中使用,或称为预处理。在下一节中,我们将首先介绍预处理的常见主题,然后讨论针对特定应用程序的预处理技术。
预处理数据
一旦数据可用,通常需要在实际的自然语言处理开始之前进行清洗或预处理。
预处理数据有两个主要目标。第一个目标是去除系统无法处理的项目——这些项目可能包括表情符号、HTML 标记、拼写错误、外语词汇或某些 Unicode 字符,如智能引号。有许多现有的 Python 库可以帮助完成这些任务,我们将在下一节去除非文本中展示如何使用它们。第二个目标在名为正则化文本的部分中讨论。我们通过正则化文本,忽略文本中与应用目标无关的词语差异。例如,在某些应用中,我们可能希望忽略大小写的差异。
有许多可能有助于准备自然语言数据的预处理任务。有些几乎是普遍需要的,如分词,而其他则仅在特定类型的应用中使用。在本节中,我们将讨论这两种类型的预处理任务。
不同的应用需要不同种类的预处理。除了最常见的预处理任务,如分词,究竟需要做哪些具体的预处理需要仔细考虑。对于某种应用而言有用的预处理步骤,可能会完全删除另一种应用所需的重要信息。因此,对于每个预处理步骤,必须考虑其目的以及它如何提高应用的有效性。特别是,如果你打算在 NLP 应用中使用大型语言模型(LLMs),你应当深思熟虑地使用预处理步骤。因为这些模型是在正常(未正则化的)文本上进行训练的,将输入文本正则化会使其与训练文本的相似度降低,通常会导致像 LLM 这样的机器学习模型出现问题。
删除非文本
许多自然语言组件只能处理文本字符,但文档中也可能包含非文本字符。根据应用的目的,你可以选择将它们完全删除,或者用系统能够处理的等效字符替换它们。
请注意,非文本的概念并不是非黑即白的。什么被视为非文本在某种程度上是特定于应用的。尽管 ASCII 字符集中的标准字符(www.ascii-code.com/
)是典型的文本示例,其他字符有时也可以被认为是非文本。例如,你的应用中的非文本可能包括货币符号、数学符号,或者以与其他文本主脚本不同的文字书写的文本(例如,在一篇英文文档中出现的中文单词)。
在接下来的两节中,我们将讨论删除或替换两种常见的非文本类型:表情符号和智能引号。这些示例应该为删除其他类型的非文本提供一个通用框架。
删除表情符号
非文本的最常见类型之一是表情符号。社交媒体帖子很可能包含表情符号,但它们对自然语言处理(NLP)来说是非常有趣的一类文本。如果你在应用中使用的自然语言工具不支持表情符号,可以将表情符号删除或用它们的文本等价物替换。在大多数应用中,你可能希望删除或替换表情符号,但在某些情况下,你的 NLP 应用可能能够直接解析它们。在这种情况下,你就不需要删除它们了。
替换表情符号的一种方法是使用正则表达式,搜索文本中表情符号的 Unicode(有关 Unicode 的更多信息,请参见 home.unicode.org/
)。然而,表情符号的集合不断扩展,因此很难编写一个能涵盖所有可能性的正则表达式。另一种方法是使用一个 Python 库,直接从 unicode.org 访问 Unicode 数据,它定义了标准的表情符号(home.unicode.org/
)。
一个可以用来删除或替换表情符号的包是 demoji
(pypi.org/project/demoji/
)。
使用 demoji
只需要安装它,然后对可能包含不需要的表情符号的文本进行处理:
-
首先,安装
demoji
:$ pip install demoji
-
然后,给定一个包含表情符号的文本,使用以下代码将表情符号替换为描述:
demoji.replace_with_desc(text)
或者,如果你想完全删除表情符号或将其替换为你选择的特定替代项,可以运行以下代码:
demoji.replace(text,replacement_text)
例如,图 5.1 显示了一个包含生日蛋糕表情符号的文本,并展示了如何用描述 :birthday cake:
替换它,或者干脆删除它:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_05_01.jpg
图 5.1 – 替换或删除表情符号
即使表情符号不会导致软件运行问题,保留表情符号意味着与表情符号相关的任何含义将被忽略,因为 NLP 软件无法理解表情符号的含义。如果表情符号被替换为描述,则可以考虑其部分含义(例如,表情符号代表生日蛋糕)。
删除智能引号
文字处理程序有时会自动将输入的引号转换为 智能引号 或 弯引号,这些引号看起来比直引号更美观,但其他软件可能无法处理这些引号。智能引号可能会导致一些自然语言处理(NLP)软件出现问题,因为这些软件可能没有预设智能引号。如果文本中包含智能引号,可以通过正常的 Python 字符串替换方法轻松替换,如以下代码所示:
text = "here is a string with "smart" quotes"
text = text.replace(""", "\"").replace(""","\"")
print(text)
here is a string with "smart" quotes
请注意,在 replace
方法中替换的直引号需要用反斜杠转义,就像任何字面量引号的使用一样。
前两节内容介绍了如何去除非文本项,如表情符号和智能引号。接下来我们将讨论一些规范化文本或修改文本以使其更统一的技巧。
规范化文本
本节将介绍一些规范化文本的最重要技巧。我们将讨论每种技巧的目标,以及如何在 Python 中应用它。
分词
几乎所有的 NLP 软件都在单词级别上操作,因此文本需要被拆分成单词才能进行处理。在许多语言中,分隔文本为单词的主要方式是空格,但也有许多特殊情况使得这个启发式方法不起作用。在图 5.2中,您可以看到用于空格拆分的代码以及使用 NLTK 进行分词的代码:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_05_02.jpg
图 5.2 – 使用 Python 代码进行空格拆分并应用 NLTK 分词
运行图 5.2中的代码将产生表 5.1中显示的分词结果:
示例 | 问题 | 根据空格拆分的结果 | NLTK 结果 |
---|---|---|---|
Walk here. | 标点符号不应包含在标记中 | ['``Walk', 'here.'] | ['Walk', '``here', '.'] |
Walk here. | 多余的空格不应计为一个标记 | ['Walk', '', '``here.'] | ['Walk', '``here', '.'] |
Don't walk here. | 缩写“don’t”应视为两个标记 | ["Don't", '``walk', 'here.'] | ['Do', "n't", 'walk', '``here', '.'] |
$``100 | $ 应作为一个单独的标记 | ['$``100'] | ['$', '``100'] |
表 5.1 – 通过拆分空格并使用 NLTK 的分词方法的分词结果
从表 5.1中,我们可以看到,仅通过空格拆分文本的简单启发式方法,在某些情况下会导致错误:
-
在表 5.1的第一行中,我们可以比较两种方法,当标点符号出现在标记的末尾,但标记与标点符号之间没有空格时。这样仅通过空格拆分标记会导致标点符号被错误地包含在标记中。这意味着
walk
、walk,
、walk.
、walk?
、walk;
、walk:
和walk!
将被视为不同的单词。如果这些单词看起来不同,那么在训练中基于某个版本的单词得出的任何泛化结果将无法应用于其他版本。 -
在第二行中,我们可以看到,如果根据空格进行拆分,连续的两个空格将导致一个额外的空白标记。这会导致任何考虑到两个单词相邻的算法产生偏差。
-
缩写也会导致问题,当使用空格拆分进行分词时。两个单词的缩写不会被分开,这意味着自然语言理解(NLU)算法无法考虑到do not和don’t有相同的含义。
-
最后,当遇到带有货币金额或其他度量单位的词时,算法无法考虑到100 美元和100 dollars有相同的含义。
很容易尝试写正则表达式来处理这些与一般化规则的例外情况,即大多数单词周围有空格。然而,在实践中,很难捕捉到所有的情况。随着我们尝试用正则表达式涵盖更多的情况,正则表达式会变得越来越复杂,也更难维护。因此,最好使用像 NLTK 这样的库,它经过多年开发并经过充分测试。你可以尝试使用不同的文本和代码,看看使用不同的分词方法会得到什么样的结果。
如表 5.1所示,不管哪种方式,结果都会是一个字符串列表,这是一种便于进一步处理的格式。
小写化
在使用大写和小写字母的语言中,大多数文档包含大写和小写字母的单词。就像分词一样,具有略微不同格式的相同单词意味着来自一种格式的数据不能适用于另一种格式的数据。例如,Walk、walk和WALK都会被视为不同的单词。为了将它们视为相同的单词,文本通常会被全部转换为小写。这可以通过循环遍历单词令牌列表并应用lower()
的 Python 函数来实现,如图 5.3所示:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_05_03.jpg
图 5.3 – 将文本转换为小写
将所有单词转换为小写确实有一些缺点。大小写的差异有时对意义很重要。最大的例子是,这会使得自然语言处理(NLP)软件难以区分专有名词和普通单词,因为它们在大小写上有所不同。如果标注器或命名实体识别器在包含大小写差异的数据上进行训练,这可能会导致词性标注(POS)或命名实体识别(NER)的错误。同样,单词有时会全大写以示强调。这可能表示句子中表达的情感——也许作者感到兴奋或愤怒——而这类信息在情感分析中可能很有帮助。出于这些原因,应该考虑每个预处理步骤在管道中的位置,以确保在需要之前不会丢失任何信息。关于这一点,将在本章后面的文本预处理管道部分详细讨论。
词干提取
许多语言中的单词根据它们在句子中的使用方式会有不同的形式。例如,英语名词根据是单数还是复数而有不同的形式,英语动词根据时态不同而有不同的形式。英语的变化形式较少,但其他语言有时会有更多。例如,西班牙语有几十种动词形式,用于表示过去、现在或未来的时态,或者动词的主语是第一、第二还是第三人称,单数还是复数。从语言学角度讲,这些不同的形式被称为屈折形态学。这些词尾被称为屈折语素。
当然,在对话或文本交流中,这些不同的形式对传达说话者的意思非常重要。然而,如果我们的 NLP 应用目标是将文档分类为不同的类别,那么关注单词的不同形式可能就不那么必要了。就像标点符号一样,单词的不同形式可能会导致它们在自然语言理解处理器中被视为完全不同的单词,尽管这些单词在意义上非常相似。
词干提取和词形还原是两种类似的正则化方法,用于处理这些不同的形式。词干提取是更简单的方法,因此我们首先讨论它。词干提取基本上意味着移除一些单词末尾的特定字母,这些字母通常但不总是屈折语素——例如,walks 末尾的 s,或 walked 末尾的 ed。词干提取算法并不了解语言中的实际单词;它们只是猜测哪些可能是词尾。因此,它们会犯很多错误。它们可能会犯错,要么删除太多字母,要么删除的字母不够,导致将实际不同的单词合并为一个,或者没有将应该视为相同单词的词合并。
PorterStemmer
是一个广泛使用的词干提取工具,并且已内置于 NLTK 中。它可以像图 5.4所示那样使用:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_05_04.jpg
图 5.4 – 使用 PorterStemmer 进行词干提取的结果
请注意,结果中包含了一些错误。虽然walked
变成了walk
,going
变成了go
,这些是正确的结果,但词干提取器做出的其他更改则是错误的:
-
exercise
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/01.pngexercis
-
every
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/01.pngeveri
-
evening
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/01.pngeven
-
this
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/01.pngthi
Porter 词干提取器也仅适用于英语,因为其词干提取算法包含了一些启发式规则,例如移除词尾的s,这些规则只适用于英语。NLTK 还包括一个多语言词干提取器,叫做 Snowball 词干提取器,可以用于更多语言,包括阿拉伯语、丹麦语、荷兰语、英语、芬兰语、法语、德语、匈牙利语、意大利语、挪威语、葡萄牙语、罗马尼亚语、俄语、西班牙语和瑞典语。
然而,由于这些词干提取器并没有对它们所应用语言的单词有具体的了解,它们可能会犯错,正如我们所看到的那样。一个类似但更准确的方法实际上是使用字典,以避免像前面列出的错误。这种方法称为 词形还原。
词形还原和词性标注
词形还原与词干提取一样,旨在减少文本中出现单词的变异。然而,词形还原实际上是用单词的词根替换每个单词(通过查阅计算词典找到词根),而不仅仅是去除看似是后缀的部分。然而,识别词根通常取决于词性,如果不知道单词的词性,词形还原可能会不准确。词性可以通过 词性标注 来识别,词性标注会将每个单词最可能的词性分配给文本中的每个单词,这在 第三章 中有所介绍。正因为如此,词形还原和词性标注通常会一起执行。
在这个例子中,我们将使用由普林斯顿大学开发的 WordNet(wordnet.princeton.edu/
),这是一个关于单词及其词性的重要信息来源。原版 WordNet 是为英语开发的,但也有针对其他语言的 WordNet。我们在 第三章 的 语义分析 部分简要提到过 WordNet,因为 WordNet 包含了语义信息以及关于词性的资料。
在这个例子中,我们将仅使用词性信息,而不使用语义信息。图 5.5 显示了导入 WordNet 词形还原器、分词器和词性标注器的过程。接着,我们需要对齐 WordNet 和词性标注器之间的词性名称,因为词性标注器和 WordNet 使用的词性名称不完全相同。然后,我们遍历文本,对每个单词进行词形还原:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_05_05.jpg
图 5.5 – 对“going for a walk is the best exercise. i’ve walked every evening this week”进行词形还原
如词形还原结果所示,输入文本中的许多单词已被替换为它们的词根——going
被替换为 go
,is
被替换为 be
,walked
被替换为 walk
。
注意,evening
没有像在词干提取示例中那样被替换为 even。如果 evening 是动词 even 的现在分词,它将被替换为 even
,但在这里,even 不是 evening 的词根。在这种情况下,evening 仅指一天中的时间。
停用词移除
停用词是非常常见的词,对于区分文档没有帮助,因此在分类应用中常常被移除。然而,如果应用涉及任何形式的详细句子分析,这些常见的词是需要的,以便系统能够理解分析的内容。
通常,停用词包括代词、介词、冠词和连词等词。哪些词应该被认为是某种语言的停用词,这个问题需要判断。例如,spaCy 的英文停用词比 NLTK 多得多(326 个 vs. 179 个)。这些特定的停用词是由 spaCy 和 NLTK 的开发者选择的,因为他们认为这些停用词在实际应用中会很有用。你可以选择你认为更方便的一个。
让我们来看看每个系统提供的停用词。
首先,为了运行 NLTK 和 spaCy 系统,你可能需要做一些初步设置。如果你在命令行或终端环境中工作,你可以通过在命令行中输入以下命令来确保 NLTK 和 spaCy 可用:
-
pip install -U pip
setuptools wheel
-
pip install -U spacy
-
python -m spacy
download en_core_web_sm
另一方面,如果你在(推荐的)Jupyter Notebook 环境中工作,环境的设置在第四章中有详细介绍,你可以在 Jupyter 代码单元中输入相同的命令,但在每个命令前加上!
。
一旦确认了你的 NLTK 和 spaCy 环境已经设置好,你可以通过运行图 5**.6中的代码来查看 NLTK 的停用词:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_05_06.jpg
图 5.6 – 查看 NLTK 的前几个停用词
注意,图 5*.6*仅显示了前几个停用词。你可以通过在你的环境中运行代码来查看所有停用词。
要查看 spaCy 的停用词,请运行图 5**.7中的代码,该代码也仅显示前几个停用词:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_05_07.jpg
图 5.7 – 查看 spaCy 的前几个停用词
比较两个包提供的停用词,我们可以看到这两个集合有很多相同之处,但也存在差异。最终,你使用哪个停用词集合取决于你。两个集合在实践中都表现良好。
删除标点符号
删除标点符号也非常有用,因为标点符号和停用词一样,出现在大多数文档中,因此并不能帮助区分文档类别。
标点符号可以通过定义一个标点符号字符串,并使用正则表达式移除字符串中的项,或者通过移除文本中每个非字母数字的词来去除。后一种方法更具鲁棒性,因为容易忽视不常见的标点符号。
删除标点符号的代码可以在图 5**.8中看到:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_05_08.jpg
图 5.8 – 删除标点符号
原始文本是text_to_remove_punct
变量的值,位于图 5.8中,其中包含几个标点符号——具体来说,是感叹号、逗号和句号。结果是tokens_no_punct
变量的值,显示在最后一行。
拼写更正
更正拼写错误是去除噪音并规范化文本输入的另一种方式。拼写错误的单词在训练数据中出现的可能性远低于正确拼写的单词,因此在处理新的文本时,它们会更难识别。此外,任何包含正确拼写单词版本的训练将无法识别或利用包含拼写错误单词的数据。这意味着值得考虑在 NLP 流程中添加拼写更正预处理步骤。然而,我们不希望在每个项目中自动应用拼写更正。以下是一些不使用拼写更正的原因:
-
有些类型的文本自然充满了拼写错误——例如,社交媒体帖子。由于拼写错误会出现在需要被应用程序处理的文本中,因此在训练或运行时数据中可能不应尝试更正拼写错误。
-
拼写错误更正并不总是做到正确的事情,导致错误单词的拼写更正是没有帮助的。它只会给处理过程引入错误。
-
有些类型的文本包含许多拼写检查器不知道的专有名词或外来词,这些词会被检查器尝试更正。再一次,这只会引入错误。
如果你选择使用拼写更正,Python 中有许多拼写检查工具可供使用。一个推荐的拼写检查器是pyspellchecker
,可以按如下方式安装:
$ pip install pyspellchecker
拼写检查代码和结果可以在图 5.9中看到:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_05_09.jpg
图 5.9 – 使用 pyspellchecker 进行拼写检查
从图 5.9中可以看出,拼写检查容易出错。pyspellchecker
正确地将agains
更正为against
,但它也犯了错误,将Ms.
更正为is
,而且它对Ramalingam
这个名字一无所知,所以没有做出任何更正。
请记住,由ASR生成的输入不会包含拼写错误,因为 ASR 只能输出字典中的单词,这些单词都是正确拼写的。当然,ASR 的输出可能会包含错误,但这些错误仅仅是由于错误的单词替代了实际说出的单词,而这些错误无法通过拼写更正来修复。
还要注意,词干提取和词形还原可能会导致出现不是实际单词的标记,而这些标记你不希望被更正。如果在处理流程中使用拼写更正,请确保它发生在词干提取和词形还原之前。
展开缩写词
增加数据统一性的另一种方法是展开缩写词——也就是说,将像don’t这样的词展开为其完整形式do not。这样,系统就能在遇到don’t时识别出do和not。
到目前为止,我们已经回顾了许多通用的预处理技术。接下来,让我们转向一些仅适用于特定类型应用的更具体的技术。
应用特定类型的预处理
我们在前面部分讨论的预处理技术通常适用于许多应用中的各种文本。对于特定应用,还可以使用额外的预处理步骤,我们将在接下来的部分中介绍这些步骤。
替换类标签为词语和数字
有时,数据中会包含一些语义等价的特定词语或标记。例如,一个文本语料库可能包括美国各州的名称,但对于该应用而言,我们只关心提到了某个州,而不在乎是哪一个。在这种情况下,我们可以用类标记替代特定的州名。请参考图 5.10中的交互:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_05_10New.jpg
图 5.10 – 类标记替换
如果我们将类标记<state_name>
替换为Texas
,那么其他州名就更容易识别了,因为系统只需要学习关于通用类<state_name>
的内容,而不是学习所有 50 个州的名称。
使用类标记的另一个原因是,如果文本包含字母数字标记,如日期、电话号码或社会安全号码,尤其是当有很多这种信息需要枚举时,可以用像<social_security_number>
这样的类标记来替代实际的号码。这还有一个附加好处,那就是可以遮掩或删减敏感信息,如具体的社会安全号码。
删减
正如我们在确保隐私和遵守伦理考量一节中讨论的那样,数据可能包含敏感信息,如人名、健康信息、社会安全号码或电话号码。在使用数据进行训练之前,应该先对这些信息进行删减。
特定领域的停用词
NLTK 和 spaCy 都具备从它们的列表中添加和删除停用词的功能。例如,如果你的应用程序中有一些非常常见的特定领域词汇,而这些词不在内建的停用词列表中,你可以将这些词添加到应用特定的停用词列表中。相反,如果一些通常被认为是停用词的词在应用程序中有实际意义,可以将这些词从停用词中移除。
一个很好的例子是词语not,在 NLTK 和 spaCy 中都是停用词。在许多文档分类应用中,将not视为停用词是可以接受的;然而,在情感分析等应用中,not及其他相关词语(例如nothing或none)可以是负面情感的重要线索。如果移除它们,则可能会导致错误,例如句子I do not like this product 变为 I do like this product。在这种情况下,您应该从您正在使用的停用词列表中移除not和其他否定词语。
移除 HTML 标记
如果应用程序基于网页,则其将包含在 NLP 中无用的 HTML 格式标记。Beautiful Soup 库(www.crummy.com/software/BeautifulSoup/bs4/doc/
)可以执行删除 HTML 标签的任务。虽然 Beautiful Soup 有许多用于处理 HTML 文档的功能,但对于我们的目的来说,最有用的功能是 get_text()
,它从 HTML 文档中提取文本。
数据不平衡
文本分类的任务是将每个文档分配给一组类别中的一个,这是最常见的 NLP 应用之一。在每个真实的分类数据集中,一些类别将比其他类别拥有更多的示例。这个问题称为数据不平衡。如果数据严重不平衡,这将导致机器学习算法出现问题。解决数据不平衡的两种常见技术是过采样和欠采样。过采样意味着复制较少频繁类别中的一些项,而欠采样意味着删除更常见类别中的一些项。这两种方法可以同时使用 - 可以对频繁类别进行欠采样,而对不频繁类别进行过采样。我们将在第十四章中详细讨论这个话题。
使用文本预处理流水线
为 NLP 准备您的数据通常涉及多个步骤,每个步骤都将前一步骤的输出添加新信息,或者通常是为 NLP 进一步准备数据。这样的预处理步骤序列称为流水线。例如,一个 NLP 流水线可以包括分词,然后是词形还原,最后是停用词移除。通过在流水线中添加和删除步骤,您可以轻松地尝试不同的预处理步骤,并查看它们是否会对结果产生影响。
流水线可用于准备用于模型学习的训练数据,以及在运行时或测试期间使用的测试数据。通常情况下,如果始终需要预处理步骤(例如分词),则值得考虑在训练数据上执行一次并保存结果数据集。如果您正在使用不同的预处理步骤配置运行实验以找到最佳配置,则这将节省时间。
选择预处理技术
表 5.2 是本章中描述的预处理技术的总结,包括它们的优缺点。每个项目都应该考虑哪些技术能够带来更好的结果:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/Table_01.jpg
表 5.2 – 预处理技术的优缺点
许多技术(如拼写校正)有可能引入错误,因为技术并不完美。对于一些较少研究的语言,相关算法的成熟度可能不如研究较多的语言。
值得一提的是,首先进行仅使用最基本技术(如分词)的初步测试,只有在初步测试结果不够好时,才引入额外的技术。有时,预处理引入的错误会导致整体结果变差。在调查过程中,保持持续评估结果非常重要,以确保结果不会变差。评估将在第十三章中详细讨论。
总结
在本章中,我们介绍了如何找到和使用自然语言数据,包括为特定应用查找数据以及使用通用可用语料库。
我们讨论了各种为自然语言处理准备数据的技术,包括注释,它为监督学习奠定了基础。我们还讨论了常见的预处理步骤,这些步骤去除了数据中的噪声并减少了数据的变化,使机器学习算法能够专注于不同类别文本之间最具信息量的差异。本章还涉及了隐私和伦理相关的议题——如何确保文本数据中包含的信息的隐私性,如何确保生成数据或标注数据的众包工作者得到公平对待。
下一章将讨论探索性技术,用于全面了解数据集,例如摘要统计(词频、类别频率等)。还将讨论可视化工具(如 matplotlib),这些工具可以提供通过查看文本数据的图形表示所能获得的最佳见解。最后,它将讨论基于可视化和统计结果可以做出的决策。
第六章:探索和可视化数据
探索和可视化数据是开发自然语言理解(NLU)应用过程中的关键步骤。在本章中,我们将探讨数据探索的技术,如可视化词频以及可视化文档相似性的技术。我们还将介绍几个重要的可视化工具,如 Matplotlib、Seaborn 和 WordCloud,这些工具使我们能够以图形方式呈现数据并识别数据集内的模式和关系。通过结合这些技术,我们可以深入了解数据,为 NLU 处理的下一步做出明智的决策,从而提高分析的准确性和效果。无论您是数据科学家还是开发人员,数据探索和可视化都是从文本数据中提取可操作洞见的关键技能,为进一步的 NLU 处理做好准备。
在本章中,我们将涵盖与数据的初始探索相关的几个主题,特别是可视化探索或可视化。我们将首先回顾几个查看数据视角的原因,以便帮助。接下来,我们将介绍一个电影评论样本数据集,用来说明我们的技术。然后,我们将探讨数据探索的技术,包括总结统计信息、可视化数据集中的词频以及测量文档相似性。最后,我们将给出一些开发可视化的一般提示,并结论关于如何使用可视化信息来做出关于进一步处理的决策的一些想法。
我们将要涵盖的主题如下:
-
为什么要可视化?
-
数据探索
-
开发可视化的一般考虑因素
-
使用可视化信息来做出关于处理的决策
为什么要可视化?
可视化数据意味着以图表或图形等图形格式显示数据。这几乎总是训练自然语言处理(NLP)系统执行特定任务的有用前提,因为通常很难在大量文本数据中看到模式。通过视觉方式通常更容易看到数据的总体模式。这些模式可能对决定最适用的文本处理技术非常有帮助。
可视化在理解自然语言处理分析结果并决定下一步操作时也很有用。由于查看自然语言处理分析结果并非初始的探索步骤,我们将把这个话题推迟到第十三章和第十四章。
为了探索可视化,在本章中,我们将使用一组文本文档数据集。文本文档将说明一个二元分类问题,该问题将在下一节中描述。
文本文档数据集 – 句子极性数据集
句子极性数据集是一个常用的数据集,包含最初来自互联网电影数据库(IMDb)的电影评论。这些评论已根据正面和负面进行分类。最常见的任务是将这些评论分类为正面和负面。数据是由康奈尔大学的一个团队收集的。有关该数据集及其数据的更多信息,请访问www.cs.cornell.edu/people/pabo/movie-review-data/
。
自然语言工具包(NLTK)将这个数据集作为其内置语料库之一。该数据集包含 1,000 条正面评论和 1,000 条负面评论。
这是这个数据集中的一个正面评论示例:
kolya is one of the richest films i've seen in some time .
zdenek sverak plays a confirmed old bachelor ( who's likely to remain so ) , who finds his life as a czech cellist increasingly impacted by the five-year old boy that he's taking care of .
though it ends rather abruptly-- and i'm whining , 'cause i wanted to spend more time with these characters-- the acting , writing , and production values are as high as , if not higher than , comparable american dramas .
this father-and-son delight-- sverak also wrote the script , while his son , jan , directed-- won a golden globe for best foreign language film and , a couple days after i saw it , walked away an oscar .
in czech and russian , with english subtitles .
这是一个负面评论的示例:
claire danes , giovanni ribisi , and omar epps make a likable trio of protagonists , but they're just about the only palatable element of the mod squad , a lame-brained big-screen version of the 70s tv show .
the story has all the originality of a block of wood ( well , it would if you could decipher it ) , the characters are all blank slates , and scott silver's perfunctory action sequences are as cliched as they come .
by sheer force of talent , the three actors wring marginal enjoyment from the proceedings whenever they're on screen , but the mod squad is just a second-rate action picture with a first-rate cast .
我们可以查看数据集中成千上万的示例,但仅通过查看单个示例很难看出任何大规模的模式;数据量太大,我们无法从细节中分辨出整体图景。接下来的章节将介绍一些可以帮助我们识别这些大规模模式的工具。
数据探索
数据探索,有时也叫做探索性数据分析(EDA),是对数据进行初步查看的过程,目的是找出数据中有哪些模式,从而对整个数据集有一个全面的认识。这些模式和总体视角将帮助我们识别最合适的处理方法。由于一些自然语言理解(NLU)技术计算开销很大,我们希望确保不会浪费大量时间应用不适合特定数据集的技术。数据探索有助于我们在项目初期就缩小技术选择的范围。可视化在数据探索中非常有帮助,因为它是一种快速了解数据模式全貌的方式。
我们想要探索的语料库中最基本的信息包括词数、不同词汇的数量、文档的平均长度以及每个类别中的文档数量等信息。我们可以从查看单词的频率分布开始。我们将介绍几种不同的可视化单词频率的方法,然后查看一些文档相似度的度量。
频率分布
频率分布显示特定类型的项目在某个上下文中出现的频率。在我们的案例中,上下文是数据集,我们将查看数据集中出现的单词的频率,然后是n-gram(单词序列)的频率。我们将从定义单词频率分布并进行一些预处理开始。然后,我们将使用 Matplotlib 工具和 WordCloud 可视化单词频率,并将相同的技术应用于 n-gram。最后,我们将介绍一些可视化文档相似度的技术:词袋模型(BoW)和 k 均值聚类。
单词频率分布
语料库中出现的单词及其频率通常包含很多有用的信息。在深入进行自然语言处理项目之前,查看这些信息是一个好主意。让我们通过使用 NLTK 来计算这些信息。我们首先导入 NLTK 和电影评论数据集,如图 6.1所示:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_01.jpg
图 6.1 – 导入 NLTK 和电影评论数据集
图 6.2 显示了我们可以用来将 movie_reviews
数据集中的单词收集到列表中的代码,并在接下来的步骤中查看一些单词:
-
为了将语料库中的单词收集到一个 Python 列表中,NLTK 提供了一个有用的函数
words()
,我们在这里使用它。 -
通过使用 Python 的
len()
函数来找出数据集中的总单词数,传入的参数是单词列表。 -
打印单词列表:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_02.jpg
图 6.2 – 制作语料库中的单词列表,统计它们,并显示前几个单词
统计单词并打印出前几个单词的结果如下所示:
1583820
['plot', ':', 'two', 'teen', 'couples', 'go', 'to', ...]
我们不会看到比前几个单词更多的单词('plot'
、':'
、'two'
等),因为有太多单词无法全部显示。通过打印列表的长度,我们可以看到数据集中有 1,583,820 个单词,显然这个数量太多,无法一一列出。我们还可以注意到,这个单词列表中包含标点符号,特别是 :
。由于标点符号非常常见,查看它们不太可能为我们提供关于文档之间差异的洞察。此外,包含标点符号也会使得我们难以看到实际上区分文档类别的单词。因此,我们需要去除标点符号。
图 6.3 显示了通过以下步骤去除标点符号的方法:
-
初始化一个空列表,用于存储去除标点符号后的新单词列表(
words_no_punct
)。 -
遍历单词列表(
corpus_words
)。 -
只保留字母数字单词。此代码在第 4 行使用了 Python 字符串函数
string.isalnum()
来检测字母数字单词,这些单词会被添加到我们之前初始化的words_no_punct
列表中。 -
一旦我们去除了标点符号,可能会对非标点符号单词的出现频率感兴趣。我们语料库中最常见的单词是什么?NLTK 提供了一个有用的
FreqDist()
函数(频率分布),可以计算单词的出现频率。这个函数在图 6.3的第 6 行中应用。 -
然后,我们可以使用 NLTK 的
most_common()
方法查看频率分布中最常见的单词,该方法的参数是我们想查看的单词数量,显示在第 8 行。 -
最后,我们打印出最常见的 50 个单词:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_03.jpg
图 6.3 – 电影评论数据库中最常见的 50 个单词及其频率
在图 6**.3中,我们可以很容易地看到the
是最常见的单词,在数据集中出现了 76,529 次,这并不令人惊讶。然而,要看到不太常见单词的频率就更难了。举个例子,看到第十个最常见的单词,以及它与第十一个最常见单词相比有多少差距,这并不容易。这就是我们引入可视化工具的原因。
我们在图 6**.3中计算的频率可以通过plot()
函数绘制频率分布图。该函数有两个参数:
-
第一个参数是我们希望查看的单词数量——在这个例子中是
50
。 -
cumulative
参数决定了我们是只想查看 50 个单词的频率(cumulative=False
),还是查看所有单词的累积频率。如果我们想查看所有单词的累积频率,我们需要将此参数设置为True
。
要绘制频率分布,我们可以简单地添加plot()
调用,代码如下:
freq.plot(50, cumulative = False)
结果如图 6**.4所示,是每个单词频率的图示,最常见的单词排在最前面:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_04.jpg
图 6.4 – 电影评论语料库中单词的频率分布
尝试使用不同数量的单词和cumulative = True
来调用freq.plot()
。当你要求查看越来越多的单词时,会发生什么呢?你会发现,查看越来越稀有的单词(通过增加第一个参数的数值)并不会提供太多见解。
虽然图 6**.4中的图表给我们提供了关于数据集中不同单词频率的更清晰概念,但它还告诉我们关于频繁单词更重要的事情。大多数这些单词,比如the
、a
和and
,并不含有太多信息。就像标点符号一样,它们很可能不会帮助我们区分我们感兴趣的类别(正面和负面评论),因为它们在大多数文档中频繁出现。这些类型的单词被称为停用词,通常会在自然语言数据中被去除,尤其是在自然语言处理(NLP)中,因为它们并没有提供太多信息。
NLTK 提供了不同语言的常见停用词列表。让我们看一下其中一些英语停用词:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_05.jpg
图 6.5 – 50 个英语停用词的示例
图 6*.5*显示了我们可以使用的代码,通过以下步骤检查英语停用词:
-
导入
nltk
和stopwords
包。 -
将停用词集合转换为 Python 列表,以便我们对其进行列表操作。
-
使用 Python 的
len()
函数查看列表的长度并打印值(179 项)。 -
打印前
50
个停用词。
NLTK 中也为其他语言提供了停用词。我们可以通过运行图 6.6中的代码来查看这些停用词列表:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_06.jpg
图 6.6 – NLTK 含停用词的语言
代码包含以下三个步骤:
-
收集包含 NLTK 停用词的语言名称。停用词存储在每个语言对应的文件中,因此获取这些文件就能获得语言名称。
-
打印语言列表的长度。
-
打印语言的名称。
一旦我们拥有了停用词的列表,就可以轻松地将它们从语料库中移除。在移除标点符号后,如我们在图 6.3中所见,我们只需遍历语料库中的单词列表,移除停用词列表中的单词,如下所示:
words_stop = [w for w in words_no_punct if not w in stop_words]
顺便提一下,将移除标点符号和停用词的操作合并为一次遍历整个单词列表会显得更加高效,在遍历过程中检查每个单词是否是标点符号或停用词,如果是,就将其移除。我们单独展示这些步骤是为了清晰起见,但在你自己的项目中,你可能想将这两个步骤合并。就像我们在移除标点符号时所做的那样,我们可以使用 NLTK 的频率分布函数,查看除了停用词之外,哪些单词最为常见,并将其显示出来,如图 6.7所示:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_07.jpg
图 6.7 – 移除标点符号和停用词后的最常见单词
我们可以在图 6.7中看到,移除停用词后,我们对电影评论语料库中的单词有了更清晰的认识。现在最常见的单词是 film
,第三常见的单词是 movie
。这正是我们从电影评论语料库中所期望的。类似的评论语料库(例如产品评论语料库)可能会显示出不同的频率分布。即便仅仅通过频率分布提供的简单信息,有时也足以完成一些 NLP 任务。
例如,在作者身份研究中,我们希望将一篇作者未知的文档归属于一个已知的作者。我们可以将该文档中单词的频率与已知作者的文档中的单词频率进行比较。另一个例子是领域分类,我们想知道该文档是电影评论还是产品评论。
使用 Matplotlib、Seaborn 和 pandas 可视化数据
虽然 NLTK 提供了一些基本的绘图功能,但还有一些其他更强大的 Python 绘图库,它们被广泛用于绘制各种数据,包括自然语言处理(NLP)数据。在本节中,我们将探讨其中一些。
Matplotlib (matplotlib.org/
) 是一个非常流行的工具。Matplotlib 可以创建多种可视化,包括动画和交互式可视化。我们将在这里使用它来创建另一个我们在 图 6.4 中绘制的数据的可视化。Seaborn (seaborn.pydata.org/
) 基于 Matplotlib 构建,是一个更高层次的接口,用于生成美观的可视化。这两个包通常还会使用另一个 Python 数据包 pandas (pandas.pydata.org/
),它非常适合处理表格数据。
对于我们的示例,我们将使用与 图 6.7 中相同的数据,但我们将使用 Matplotlib、Seaborn 和 pandas 来创建可视化。
图 6.8 显示了此示例的代码:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_08.jpg
图 6.8 – 收集前 25 个常见词的 Python 代码,移除标点符号和停用词后
图 6.8 显示了绘制数据的准备代码,包括以下步骤:
-
导入 NLTK、pandas、Seaborn 和 Matplotlib 库。
-
将频率截止设置为
25
(这可以是我们感兴趣的任何数字)。 -
计算没有停用词的语料库单词的频率分布(第 7 行)。
我们首先导入 NLTK、pandas、Seaborn 和 Matplotlib。我们将频率截止设置为 25
,因此我们只会绘制前 25 个最常见的单词,并且在第 7 行获得我们的数据的频率分布。
生成的图表显示在 图 6.9 中:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_09.jpg
图 6.9 – 在移除标点符号和停用词后,使用 Matplotlib、Seaborn 和 pandas 库显示的最常见单词
图 6.7 和 图 6.9 显示的是相同的数据。例如,每个图中最常见的单词是 film
,接着是 one
,然后是 movie
。为什么要选择一种可视化工具而非另一种呢?其中一个区别是,在 图 6.9 中,似乎更容易看到某个特定单词的信息,这可能是由于条形图格式,每个单词都有对应的条形图。而在 图 6.7 中,由于线条并不清晰,因此稍微难以看到每个单词的频率。
另一方面,由于连续的线条,图 6.7 中的整体频率分布更容易看到。因此,选择一种可视化方式而非另一种,实际上取决于你想要强调的信息类型。当然,如果你希望以不同的方式查看数据,完全没有理由只局限于一种可视化方式。
顺便提一下,在两个图中的模式,最常见的单词具有非常高的频率,较不常见的单词频率急剧下降,这种模式在自然语言数据中非常常见。这个模式说明了一个叫做齐夫定律的概念(关于这个概念的更多信息,见en.wikipedia.org/wiki/Zipf%27s_law
)。
查看另一种频率可视化技术——词云
词云是另一种可视化单词相对频率的方法。词云以不同的字体大小显示数据集中的单词,频率较高的单词以较大的字体显示。词云是一个很好的方法,可以让常见单词在视觉上更加突出。
图 6.10中的代码展示了如何导入WordCloud
包并从电影评论数据创建词云:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_10.jpg
图 6.10 – 显示最常见单词的 Python 代码,作为词云呈现
代码展示了以下步骤:
-
我们在第 2 行导入了一个新的库
WordCloud
。对于此显示,我们将仅选择最常见的 200 个单词(在第 6 行设置了频率阈值200
)。 -
我们在第 7 行创建了一个频率分布。
-
频率分布在第 8 行被转换为 pandas Series。
-
为了减少非常短单词的数量,我们在第 10 行只包括长度大于两个字母的单词。
-
第 11 行的代码生成了词云。
colormap
参数指定了许多 Matplotlib 颜色映射之一(颜色映射的文档在matplotlib.org/stable/tutorials/colors/colormaps.html
)。你可以尝试不同的配色方案,找到你喜欢的样式。 -
第 12-14 行格式化图表区域。
-
最后,图表在第 15 行显示。
图 6.11展示了来自图 6.10中代码生成的词云:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_11New.jpg
图 6.11 – 电影评论中单词频率的词云
如我们在图 6.7和图 6.9中看到的,最常见的单词是film
、one
和movie
。然而,词云可视化使得最常见的单词以图表无法比拟的方式脱颖而出。另一方面,词云中频率较低的单词很难区分。例如,从词云中很难判断good
是否比story
更常见。这又是一个例子,说明在选择可视化方式之前,你应该考虑希望从中获取什么信息。
下一部分将展示如何更深入地挖掘数据,获取一些关于数据子集(如积极和消极评论)的洞见。
积极与消极的电影评论
我们可能想要查看电影评论的不同类别(正面和负面)之间的差异,或者更一般地,查看任何不同类别之间的差异。例如,正面和负面评论中的常见词是否不同?对正面和负面评论属性的初步分析可以让我们更好地理解这些类别的差异,这反过来可能帮助我们选择合适的方法,使训练好的系统能够自动区分这些类别。
我们可以使用任何基于频率分布的可视化方式,包括图 6**.7中的折线图,图 6*.9中的条形图,或图 6**.11*中的词云可视化。在这个例子中,我们将使用词云,因为它是查看两种频率分布之间单词频率差异的好方法。
查看图 6**.12中的代码,我们首先导入所需的库:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_12.jpg
图 6.12 – 导入用于计算词云的库
接下来我们将创建两个函数,方便我们对语料库的不同部分执行类似的操作:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_13.jpg
图 6.13 – 计算词云的函数
图 6*.13*中的第一个函数clean_corpus()
会从语料库中移除标点符号和停用词。第二个函数plot_freq_dist()
会从频率分布中绘制词云。现在我们准备好创建词云了:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_14New.jpg
图 6.14 – 显示正面和负面评论词频的代码
我们通过以下步骤创建词云:
-
现在我们已经定义了函数,将语料库分为正面和负面评论。这是在第 28 行和第 29 行的代码中完成的。
-
与我们在图 6**.2中看到的要求获取语料库中所有单词不同,我们请求获取特定类别的单词。在这个例子中,类别是正面(
pos
)和负面(neg
)。 -
我们在第 28 行和第 29 行的每一组词中移除停用词和标点符号。
-
接下来,我们在第 30 行和第 31 行为正面和负面词创建频率分布。最后,我们绘制词云。
图 6*.15* 显示了正面评价的词云:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_15New.jpg
图 6.15 – 在词云中显示正面评价的词频
图 6*.16* 显示了在词云中显示负面评价的词频:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_16New.jpg
图 6.16 – 在词云中显示负面评价的词频
比较图 6.15和图 6.16与图 6.11中的原始词云,我们可以看到,film
、one
和 movie
是正面和负面评论中最常出现的词,也是总体最常出现的词,因此它们在区分正负面评论方面不会很有用。
词语good
在正面评论词云中的大小(因此也更为频繁)大于在负面评论词云中的出现频率,这正是我们所期望的。然而,good
在负面评论中也出现得相当频繁,因此它绝不是判断正面评论的明确标志。其他的差异则不太符合预期——例如,story
在正面评论中更常见,尽管它也会出现在负面评论中。这一比较表明,仅通过简单的关键词识别技术,区分正负面评论的问题可能无法得到解决。
我们将在第九章和第十章中探讨的技术,将更适合解决将文本分类到不同类别的问题。然而,我们可以看到,这一开始的词云探索对于排除基于简单关键词的方法非常有用。
在下一节中,我们将查看语料库中的其他频率。
查看其他频率度量
到目前为止,我们只看了词频,但我们可以查看任何其他可以度量的文本特征的频率。例如,我们可以查看不同字符或不同词性出现的频率。你可以尝试扩展本章前一部分词频分布中展示的代码,去统计电影评论文本中的一些其他特征。
语言的一个重要特性是,单词不仅仅是孤立地出现——它们会以特定的组合和顺序出现。单词的意思可以根据它们的上下文发生显著变化。例如,not a good movie 与 a good movie 的含义截然不同(实际上是相反的含义)。有许多技术可以考虑单词的上下文,我们将在第八章到第十一章中探讨这些技术。
然而,在这里我们将仅描述一种非常简单的技术——观察彼此相邻的单词。当两个单词一起出现时,称之为ngrams()
,它接受一个n
值作为参数。图 6.17展示了计算和显示电影评论语料库中 n-gram 的代码:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_17.jpg
图 6.17 – 计算电影评论数据中的二元组
代码显示了以下初始化步骤:
-
我们首先导入
nltk
、ngrams
函数以及电影评论语料库。 -
我们将频率截止值设置为
25
,但和之前的例子一样,这个值可以是我们认为有趣的任何数字。 -
我们在第 8 行收集了语料库中的所有单词(如果我们只想要正面评论中的单词或负面评论中的单词,我们可以通过设置
categories = 'neg'
或categories = 'pos'
来获取这些单词,正如我们在图 6.14中看到的)。 -
最后,我们在第 11 行使用在图 6.13中定义的
clean_corpus
函数,移除标点符号和停用词。
在图 6.18中,我们收集了二元组:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_18.jpg
图 6.18 – 计算电影评论数据中的二元组
二元组的收集步骤如下:
-
ngrams()
函数在第 14 行使用,并传入参数2
,表示我们想要二元组(即两个相邻单词的组合)。这里可以使用任何数字,但非常大的数字可能不会非常有用。这是因为随着n
值的增加,符合该值的 ngram 会越来越少。到某个程度时,某个特定的 ngram 可能没有足够的示例来提供关于数据模式的信息。二元组或三元组通常在语料库中足够常见,因此有助于识别模式。 -
在第 21 至 23 行,我们遍历二元组列表,从每一对中创建一个字符串。
在图 6.19中,我们制作了二元组的频率分布并展示了它。
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_19.jpg
图 6.19 – 显示电影评论数据中的二元组
-
我们在第 29 行使用熟悉的 NLTK
FreqDist()
函数对二元组列表进行处理,并将其转换为 pandas Series。 -
剩下的代码设置了 Seaborn 和 Matplotlib 中的条形图,并在第 39 行显示了它。
由于我们使用的频率截止值为25
,因此我们只会查看最常见的 25 个二元组。你可能想尝试不同的更大或更小的频率截止值。
图 6.20 显示了我们在图 6.19中计算的图表结果。由于二元组通常比单个词更长,占用更多空间,因此我们交换了 x 和 y 轴,使得二元组的计数显示在 x 轴上,而单个二元组显示在 y 轴上:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_20.jpg
图 6.20 – 按频率排序的电影评论数据中的二元组
图 6.20揭示了语料库中一些有趣的事实。例如,最常见的双字组special effects
在语料库中出现约 400 次,而最常见的单词film
则出现了将近 8000 次。这是可以预期的,因为两个单词必须一起出现才能算作一个双字组。我们还看到,许多双字组例如New York
和Star Trek
出现在这个列表中。其他的双字组并非习语,而只是常见短语,如real life
和one day
。在这个列表中,所有的双字组都非常合理,在电影评论的语料库中看到它们并不令人惊讶。
作为练习,尝试比较正面和负面电影评论中的双字组。在查看单词频率时,我们发现正面和负面评论中最常见的词汇是相同的。那么,最常见的双字组是否也是如此呢?
本节介绍了一些通过简单的测量方法(如计算单词和双字组)来洞察我们数据集的方式。还有一些有用的探索性技术,可以用来衡量和可视化数据集中文档之间的相似性。我们将在下一节中介绍这些技术。
衡量文档之间的相似性
到目前为止,我们一直在使用诸如折线图、条形图和词云等工具来可视化语料库中各种属性的频率,如单词和双字组。可视化文档相似性也非常有意义——也就是说,数据集中的文档彼此之间的相似程度。有很多方法可以衡量文档的相似性,我们将在后续章节中详细讨论,尤其是第九章、第十章、第十一章和第十二章。我们将在这里简单介绍两种基本的技术。
BoW 和 k-means 聚类
现在,我们将使用一个非常简单的概念,叫做词袋模型(BoW)。BoW 的核心思想是,相似的文档会包含更多相同的单词。对于语料库中的每个文档和每个单词,我们会查看该单词是否出现在该文档中。任何两个文档中共同出现的单词越多,它们就越相似。这是一个非常简单的度量方法,但它能为我们提供一个基本的文档相似性度量,便于我们展示文档相似性的可视化效果。
图 6*.21*中的代码计算了电影评论语料库的 BoW。此时你不需要关注代码的细节,因为它只是获取语料库相似度度量的一种方式。我们将使用这个相似度度量(即 BoW)来查看任意两篇文档之间的相似度。BoW 指标的优点是易于理解和计算。虽然它不是衡量文档相似度的最先进方法,但作为一个快速的第一步,它依然有用:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_21.jpg
图 6.21 – 设置 BoW 计算
图 6*.21* 显示了从语料库中获取最常见的 1,000 个单词并将它们制作成列表的过程。我们希望保留的单词数量有些随意——一个非常长的列表会减慢后续处理速度,并且也开始包含一些不会提供太多信息的稀有单词。
下一步,如图 6**.22所示,是定义一个函数来收集文档中的单词,然后列出文档:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_22.jpg
图 6.22 – 收集出现在文档中的单词
图 6*.22* 中的 document_features()
函数通过遍历给定的文档,创建一个 Python 字典,其中单词作为键,1 和 0 作为值,取决于该单词是否出现在文档中。然后,我们为每个文档创建一个特征列表,并在图 6**.23中显示结果:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_23.jpg
图 6.23 – 计算所有文档的完整特征集并显示结果 BoW
尽管每个文档的特征列表包括其类别,但我们在显示 BoW 时并不需要类别,因此我们在第 34-39 行删除了它。
我们可以在图 6**.24中看到结果 BoW 本身的前 10 个文档:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_24.jpg
图 6.24 – 电影评论语料库的 BoW
在图 6**.24中,0 和 1 的 10 行每一行代表一个文档。每个单词在语料库中都有一个对应的列。共有 1,000 列,但由于太多无法显示,我们只能看到前几列和后几列。单词按照频率排序,我们可以看到最常见的单词(film
、one
和 movie
)与我们之前在单词频率分析中找到的最常见单词(去除停用词)一致。
每个文档在 BoW 中由一行表示。这些行中的数字列表是一个向量,这是自然语言处理(NLP)中的一个非常重要的概念,我们将在后续章节中看到更多的应用。向量用于将文本文档或其他基于文本的信息表示为数字。将单词表示为数字为分析和比较文档打开了许多机会,而这些操作在文本文档的形式下是非常困难的。显然,相比于原始的文本表示,BoW 丢失了很多信息——例如我们无法知道文本中的哪些词语彼此接近——但在许多情况下,使用 BoW 的简便性超过了丢失一些文本信息的缺点。
使用向量来捕捉文档相似性是一个非常有趣的方式,包括 BoW 向量。这是探索数据集的第一步,并且非常有用。如果我们能知道哪些文档与其他文档相似,就可以根据相似性将它们分类。然而,仅仅看图 6.24中的文档向量并不能提供太多的洞见,因为很难看出任何模式。我们需要一些可视化文档相似性的工具。
一种很好的可视化文档相似性的方法是 k-means 聚类。k
值指的是我们想要的聚类数量,由开发者选择。在我们的例子中,由于我们有 2 个已知类别,对应于正面和负面的评论集,所以我们将从2
开始作为k
的值。
图 6.25展示了计算并显示我们在图 6.23中计算的 BoW 的 k-means 聚类结果的代码。我们不必深入讨论图 6.25中的代码,因为它将在第十二章中详细介绍。然而,我们可以注意到,这段代码使用了另一个重要的 Python 机器学习库sklearn
,用于计算聚类:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_25.jpg
图 6.25 – 设置 k-means 聚类
第一步是导入我们需要的库,并设置我们希望的聚类数量(true_k
)。
代码的下一部分,如图 6.26所示,计算 k-means 聚类。
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_26.jpg
图 6.26 – 基于 BoW 可视化文档相似性的 k-means 聚类
计算聚类的步骤如图 6.26所示如下:
-
将维度降至
2
以进行显示。 -
初始化一个
kmeans
对象(第 13 行)。 -
计算结果(第 18 行)。
-
获取结果中的标签。
最后的步骤是绘制聚类图:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_27.jpg
图 6.27 – 绘制 k-means 聚类图
图 6*.27*通过迭代各个聚类,并以相同的颜色打印每个聚类中的项目,来绘制聚类图。
使用 K-means 聚类对电影评论的 BoW 进行处理的结果,可以在图 6**.28中看到:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_28.jpg
图 6.28 – 对电影语料库进行二类 K-means 聚类
在图 6**.28中,有两个主要的聚类,一个位于y轴的 0 点上方,另一个位于下方。颜色是根据第 21 行的 Matplotlib Accent
颜色映射定义的。(关于 Matplotlib 中可用的多种颜色映射的更多信息,可以参考matplotlib.org/stable/tutorials/colors/colormaps.html
。)
图 6*.28中的每个点代表一个文档。由于这些聚类明显分离,我们可以有一定信心认为相似性度量(BoW)反映了两个文档类别之间的某些真实差异。然而,这并不意味着该数据的最有意义的类别数一定是两个。检查其他类别数始终是值得的,也就是说,检查k
的其他值。通过更改图 6**.25中第 7 行的true_k
值,可以轻松做到这一点。例如,如果我们将true_k
的值更改为3
,从而指定数据应该分成三个类别,那么我们将得到一个类似图 6**.29*中的图表:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_29.jpg
图 6.29 – 对电影语料库进行三类 K-means 聚类
在图 6**.29中,确实有三个明显的类别,尽管它们的分离度不如图 6**.28中的类别那么明显。这可能意味着积极和消极评论这两个类别并没有讲述完整的故事。也许实际上应该有第三类中立评论?我们可以通过查看三个聚类中的文档来调查这一点,尽管我们这里不会进行这个操作。
通过比较图 6.28和图 6.29中的结果,我们可以看到,初步的数据探索对于决定如何将数据集分成多少类别非常有用。我们将在第十二章中详细讨论这个话题。
到目前为止,我们已经看到了一些可视化数据集信息的方法,包括词频和双词频,以及一些文档相似性的初步可视化。
现在让我们考虑一些关于可视化总体过程的要点。
开发可视化时的一般考虑事项
从我们迄今为止回顾的具体技术中稍微退一步,我们接下来将讨论一些关于可视化的总体考虑。具体来说,在接下来的几节中,我们将讨论测量什么,接着是如何表示这些测量及它们之间的关系。由于最常见的可视化是基于在XY平面中以二维形式表示信息,我们将主要聚焦于这种格式的可视化,首先从测量选择开始。
在测量之间进行选择
几乎所有的自然语言处理(NLP)都从测量我们分析的文本的某些属性开始。本节的目标是帮助你理解在 NLP 项目中可用的不同文本测量方法。
到目前为止,我们主要关注涉及单词的测量。单词是一个自然的测量属性,因为它们容易准确计数——换句话说,计数单词是一种稳健的测量方法。此外,单词直观地代表了语言的一个自然方面。然而,单纯只看单词可能会忽视文本含义中的重要属性,比如那些依赖于考虑单词顺序及其与文本中其他单词关系的属性。
为了捕捉更丰富的信息,这些信息考虑到单词的顺序及其关系,我们可以测量文本的其他属性。例如,我们可以统计字符、句法结构、词性、n-grams(词组序列)、命名实体的提及以及词的词根形式。
举个例子,我们可以研究代词在正面电影评论中是否比负面电影评论中更常见。然而,关注这些更丰富属性的缺点是,和计数单词不同,测量更丰富属性的稳健性较差。这意味着它们更容易出现错误,从而使得测量不够准确。例如,如果我们通过词性标注的结果来统计动词,一个本应为名词的错误动词标注会使得动词计数不准确。
基于这些原因,决定测量什么并不总是一个简单明了的决定。有些测量方法,如基于单词或字符的测量,虽然非常稳健,但却排除了可能重要的信息。其他测量方法,如统计词性,虽然稳健性差,但信息量更大。因此,我们无法为选择测量方法提供硬性规则。不过,一个经验法则是,从最简单且最稳健的方法开始,比如计数单词,看看你的应用在这些技术下是否能正常工作。如果可以,你就可以坚持使用这些简单的方法。如果不行,你可以尝试使用更丰富的信息。你还应记住,你并不只限于使用一种测量方法。
一旦你选择了要测量的内容,还有其他与可视化你的测量有关的常见考虑因素。在接下来的章节中,我们将讨论如何在XY平面上表示变量、不同种类的尺度以及降维方法。
从表示独立变量和依赖变量中获得的见解
大多数测量涉及测量一个good
,如果它包含bad
,我们可以判断它是负面的。我们可以通过查看正面和负面评论中的good
和bad
的计数(依赖变量)来验证这个假设,正如在图 6.30中所示:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_30.jpg
图 6.30 – 正面和负面评论中“good”和“bad”的计数
x轴上的列分别代表包含good
的正面评论、包含good
的负面评论、包含bad
的正面评论以及包含bad
的负面评论。显然,假设good
表示正面评论,而bad
表示负面评论是错误的。实际上,good
在负面评论中出现的频率高于bad
。这种探索和可视化有助于我们在项目开始时排除那些不太可能有成果的研究方向。一般来说,像图 6.30这样的条形图是表示分类独立变量或数据的好方法,这些数据出现在不同的类别中。
在查看了如图 6.30中依赖变量和独立变量的值在图形中的展示后,我们可以转向另一个常见的考虑因素:线性尺度与对数尺度。
对数尺度与线性尺度
有时你会看到一个模式,如图 6.4和图 6.7所示,其中* x轴的前几个项具有非常高的值,而其他项的值迅速下降。这使得我们很难看到图形右侧的部分,那里项的值较低。如果我们看到这种模式,那么它暗示了对数尺度可能比图 6.2中的线性尺度更适合用在 y轴上。我们可以在图 6.7的数据显示中看到对数尺度,见图 6.31*:
https://github.com/OpenDocCN/freelearn-dl-pt5-zh/raw/master/docs/nlu-py/img/B19005_06_31.jpg
图 6.31 – 图 6.4中数据的对数尺度可视化
图 6.31展示了图 6.7中数据的对数尺度图。y轴的值是按等距 10 的幂次排列的 50 个最常见单词的计数,因此y轴上的每个值都是前一个值的 10 倍。与图 6.7相比,我们可以看到表示频率计数的线更加平坦,特别是在右侧。在对数显示中,更容易比较这些较不常见但仍然非常频繁的单词的频率。因为即使在这个图表中最不常见的单词she
,在数据集中也出现了超过 3,000 次,所以这条线没有低于 10³。
如果你看到像图 6.7中的模式,你应该考虑将数据以对数尺度显示的选项。
到目前为止,我们一直在查看可以轻松显示在纸面或平面屏幕上的二维数据。如果我们有超过两个维度的情况会怎样呢?让我们现在考虑更高维度的数据。
维度与降维
到目前为止,我们看到的示例大多是带有x和y轴的二维图表。然而,许多 NLP 技术会产生维度更高的数据。虽然二维数据容易绘制和可视化,但更高维度的数据可能更难理解。三维数据可以通过添加z轴并旋转图形使x和z轴在显示屏上呈 45 度角来显示。通过给屏幕图形加上动画,并显示随时间变化的情况,可以增加第四维或时间维度。然而,四维以上的维度对于人类来说几乎不可能可视化,因此无法以有意义的方式展示它们。
然而,在许多情况下,事实证明可以去除 NLP 结果中的一些高维度,而不会严重影响 NLP 所生成的可视化效果或信息。这就是所谓的降维。降维技术用于从数据中去除不太重要的维度,以便能够更有意义地展示数据。我们将在第十二章中更详细地讨论降维。
请注意,图 6.28和图 6.29中的降维是为了将结果显示在二维页面上。
本章的最后一个主题讨论了我们可以从可视化中学到的一些内容,并包括一些使用可视化来决定如何继续进行 NLP 项目下阶段的建议。
利用可视化中的信息来做出处理决策
本节包括了如何利用可视化来帮助我们做出处理决策的指导。例如,在决定是否删除标点符号和停用词时,探索单词频率的可视化方法,如频率分布图和词云,可以告诉我们是否有非常常见的单词掩盖了数据中的模式。
查看不同数据类别的词汇频率分布可以帮助排除基于简单关键词的分类技术。
不同类型项的频率,例如词汇和二元组,能够提供不同的见解。还可以探索其他类型项的频率,比如词性或句法类别(如名词短语)。
使用聚类展示文档相似性可以帮助我们洞察出将数据集划分为最有意义的类别所需要的类别数。
最后一节总结了我们在本章中学到的信息。
总结
在本章中,我们了解了一些用于初步探索文本数据集的技术。我们首先通过查看词汇和二元组的频率分布来探索数据。接着讨论了不同的可视化方法,包括词云、条形图、折线图和聚类图。除了基于词汇的可视化方法,我们还了解了用于展示文档相似性的聚类技术。最后,我们总结了开发可视化时的一些考虑因素,并总结了通过不同方式可视化文本数据所能获得的见解。下一章将介绍如何选择分析自然语言理解(NLU)数据的方法,以及两种文本数据表示方式——符号表示和数值表示。