自然语言处理真SKR有趣!!!

图灵汇官网

计算机擅长处理结构化的数据,如电子表格和数据库表,但人类日常交流则主要依赖于词汇而非表格。因此,让计算机理解人类语言并非易事。

虽然我们的世界充满了非结构化的信息,不仅仅是原始文本,还包括各种人类语言,但如何让计算机理解这些文本并从中提取有用的信息呢?

自然语言处理(NLP)是人工智能的一个分支,旨在使计算机能够理解和处理人类语言。本文将探讨NLP的工作原理,并教你如何使用Python编写程序,从原始文本中提取信息。

如果你对NLP的具体工作原理不感兴趣,只想快速复制代码,可以直接跳到“用Python处理NLP管道”部分。

计算机能否理解语言?

自计算机问世以来,程序员们一直在尝试编写能够理解语言的程序。其中原因显而易见:几千年来,人类都是通过书写来记录事件,如果计算机能够读取并理解这些数据,将会极大地造福人类。

当前,计算机还不能像人类一样完全理解英语,但它们已经在很多方面取得了进展。在特定领域,NLP技术的应用几乎如同魔法一般。利用NLP技术,你可以节省大量时间和精力。

幸运的是,最新的NLP进展使得通过开源的Python库,如spaCy、textacy和neuralcoref,可以轻松使用这些工具。只需编写几行代码即可实现所需功能。

从文本中提取含义的挑战

阅读和理解英语的过程非常复杂,即使不考虑其逻辑性和一致性。例如,新闻标题“环境监管机构盘问了非法烧烤的业主”可能让人困惑。监管机构是在询问业主,还是在烧烤业主?由此可见,计算机解析英语是一件相当复杂的事情。

在机器学习中,处理复杂问题通常需要构建一个管道。这种方法是将问题分解成小部分,然后分别用机器学习解决每一部分。再将这些部分组合起来,从而解决复杂的问题。

我们将采取同样的策略来处理NLP。我们将理解英语的过程分解成多个小块,并逐一研究。

构建NLP管道的步骤

让我们来看一段来自维基百科的文字:

伦敦是英格兰的首都,也是英国人口最多的城市。它位于英国大不列颠岛东南部的泰晤士河边,已有两千年的主要居住历史。这座城市由罗马人建立,并被命名为伦蒂尼恩。

这段文字包含了几个有用的信息。如果计算机能够阅读这段文字并理解伦敦是一座由罗马人建立的城市,那将非常理想。但要达到这个要求,我们需要先将基本的知识教给计算机,然后逐步深入。

步骤一:句子分割

第一步是将文本分割成独立的句子。这样,我们可以得到以下句子: - “伦敦是英格兰的首都,也是英国人口最多的城市。” - “它位于泰晤士河边,已有两千年的主要居住历史。” - “这座城市由罗马人建立,并被命名为伦蒂尼恩。”

我们假设每个句子都代表一个独立的思想。相比于理解整篇文章的程序,理解独立句子的程序更容易实现。

句子分割可以通过使用标点符号来实现。然而,现代NLP管道通常需要更复杂的技术来处理格式不整齐的文档。

步骤二:分词

现在我们已经把文档分割成了句子,可以逐句处理。我们从文档的第一个句子开始:

“伦敦是英格兰的首都,也是英国人口最多的城市。”

接下来,我们将这个句子分割成独立的单词或符号,这称为分词。以下是分词的结果:

“伦敦”、“是”、“英格兰”、“的”、“首都”、“也是”、“英国”、“人口”、“最多”、“的城市”。

在英语中,分词相对简单。我们只需根据空格分割词语,并将标点符号视为单词的一部分,因为它们也有含义。

步骤三:词性标注

接下来,我们需要猜测每个词的属性,如名词、动词和形容词等。了解每个词在句子中的角色有助于推断句子的含义。

词性标注可以通过将每个词及其上下文提供给预先训练的词性分类模型来实现。词性分类模型最初通过数百万个带有词性标注的英语句子进行训练,从而学会模仿这种标注行为。

记住,这个模型是基于统计数据的,它并不是以与人类相同的方式理解词的含义。它只知道如何根据之前标记的类似单词和句子来猜测语句的含义。

处理完整个句子后,我们得到以下结果:

根据这些信息,我们可以开始收集一些基本含义。例如,这个句子中的名词包括“伦敦”和“首都”,因此这个句子很可能与伦敦有关。

步骤四:词形还原

在英语和其他大多数语言中,同一个词可能会有不同的形式。例如:

  • “我有一匹小马。”
  • “我有两匹小马。”

两句话都提到名词“小马”,但形式不同。知道词语的基本形式有助于计算机处理文本,这样就能知道这两句话在讨论同一个概念。否则,“小马”和“小马”对计算机来说就像两个完全不相关的词。

在NLP中,这个过程称为词形还原,即找出句子中每个词的基本形式或词元。

对于动词也是一样。我们可以通过寻找动词的原始非结合形式来进行词形还原。因此,“我有两匹小马”变为“我有两匹小马”。

词形还原通常通过具有基于词性的词汇形式的查找表来完成,也可能包含一些自定义规则来处理以前未见过的词语。

以下是经过词形还原后的句子:

唯一的变化是将“是”变为“be”。

步骤五:识别停用词

接下来,我们需要考虑句子中每个词的重要性。英语中有许多高频出现的填充词,如“和”、“的”、“一个”等。这些词在文本分析中出现频率很高,容易产生歧义。一些NLP管道会将这些词标记为停用词,即在进行任何分析之前需要过滤掉的词。

以下是过滤掉停用词后的句子:

停用词的识别通常通过查询一个硬编码的已知停用词列表来完成。然而,不存在适用于所有应用场景的标准停用词列表,这个列表很大程度上取决于你的应用需求。

例如,如果你正在开发一个与摇滚乐队相关的搜索引擎,需要确保你没有忽略“the”这个词。不仅因为这个词经常出现在乐队名中,还有一个著名的摇滚乐队叫做“The The”。

步骤六:依存句法分析

下一步是找出句子中每个词之间的依存关系,这被称为依存句法分析。

我们的目标是构建一棵树,为句子中的每个词赋予一个父类词。树的根是句子的主要动词。根据这个句子构造的解析树如下:

然而,我们还可以做得更多。为了识别每个词的父类词,我们还需要预测这两个词之间的关系:

这棵解析树显示,这个句子的核心是名词“伦敦”,它和“首都”之间有“be”的关系。我们最终发现了一些有用的信息——伦敦是一个首都!如果我们遵循这个句子的整棵解析树,甚至可以发现伦敦是英国的首都。

就像我们早前使用机器学习模型来预测词性一样,我们可以通过将词语输入机器学习模型并输出结果的方式来完成依存句法分析。但是,依存句法分析是一项复杂的任务,需要一整篇文章来详细讨论其工作原理。如果你对此感兴趣,可以阅读Matthew Honnibal的一篇优秀文章《用500行Python代码解析英语》。

然而,尽管Honnibal在2015年指出这种方法已经成为标准,但它已经过时,甚至不再被作者使用。2016年,谷歌推出了一种新的依存句法分析方法,称为Parsey McParseface,采用了新的深度学习方法,超越了之前的表现,并在业界迅速传播。一年后,他们发布了新的模型,称为ParseySaurus,进一步改进了某些方面。换句话说,解析技术仍然是搜索领域的一项热门技术,并且在不断变化和改进。

步骤七:命名实体识别(NER)

现在我们已经完成了所有困难的工作,终于可以抛弃书面语法并开始实现想法了。

在我们的句子中,有以下名词:

这些名词中,有些代表了实际意义。比如,“伦敦”、“英格兰”和“英国”代表了物理位置。如果能检测到这些信息,那真是太棒了!有了这些信息,我们可以使用NLP自动提取文档中提及的真实世界地理位置列表。

命名实体识别(NER)的目标是为了检测和标记这些代表真实世界中某些事物的名词。在使用我们的NER标记模型处理句子中的每个词后,句子变成了这样:

但是,NER系统不仅仅做简单的查找字典的工作。它使用某个词语在句子中的上下文以及统计模型来猜测该词语代表哪种类型的名词。一个优秀的NER系统可以根据上下文线索辨别出人名“Brooklyn Decker”和地名“Brooklyn”。

NER系统通常标记以下经典类型的事物:

  • 人名
  • 公司名
  • 地理位置(物理位置和政治位置)
  • 产品名称
  • 日期和时间
  • 金额
  • 事件名称

自从NER能够帮助轻易地从文本中获取结构化数据,它就被广泛使用。它是从NLP管道中获得结果的最便捷途径之一。

步骤八:共指解析

在这个阶段,我们已经对句子有了充分的理解。我们了解了每个词的词性、词之间的依存关系以及哪些词是命名实体。

然而,我们还需要解决一个大问题。英语中有大量的代词,如“他”、“她”和“它”。这些词是对反复出现的名词的简化。人们可以根据上下文推断出这些词的含义,但我们的NLP模型却不知道这些代词的含义,因为它每次只检查一个句子。

来看我们的文档中的第三个句子:

“它由罗马人建立,取名为伦蒂尼恩。”

如果我们用NLP管道解析这个句子,我们知道“它”是由罗马人建立的。但如果知道“伦敦”是由罗马人建立的,那将更有用。

当我们阅读这个句子时,很容易得出“它”代表“伦敦”。共指解析的目的是根据整个句子中的代词来找出这种相同的映射。我们希望找出所有指向同一实体的词语。

这是在我们的文档中对“伦敦”使用共指解析的结果:

将共指信息、解析树和命名实体信息结合起来,我们可以从文档中提取出许多信息!

共指解析是我们正在进行的管道中最难的步骤之一。它甚至比句法分析还要困难。最新的深度学习进展带来了更精确的方法,但它还不完美。如果你想了解更多它是如何工作的,可以从这里开始。

使用Python构建NLP管道

这是我们完整的NLP管道的概览:

共指解析是一个可选步骤,不一定总是需要完成。

注意:在我们继续之前,值得注意的是,这些都是构建传统NLP管道的步骤,你可以根据你的目的以及如何实现你的NLP库来决定是跳过还是重复某些步骤。例如,一些像spaCy这样的库是先使用依存句法分析,然后进行句子分割。

那么,我们如何构建这个管道?多亏了像spaCy这样的神奇Python库,构建管道的工作已经完成!所有的步骤都已完成,随时准备为你所用。

首先,假设你已经安装了Python 3,你可以按照以下步骤安装spaCy:

```sh

安装spaCy

pip3 install -U spacy

下载针对spaCy的大规模英语模型

python3 -m spacy download encoreweb_lg

安装同样有用的textacy

pip3 install -U textacy ```

在一段文档中运行NLP管道的代码如下所示:

```python import spacy

加载大规模英语模型

nlp = spacy.load('encoreweb_lg')

我们想要检验的文本

text = """伦敦是英格兰的首都,也是英国人口最多的城市。它位于泰晤士河边,已有两千年的主要居住历史。这座城市由罗马人建立,并被命名为伦蒂尼恩。"""

用spaCy解析文本。在整个管道运行。

doc = nlp(text)

'doc'现在包含解析后的文本。我们可以用它来做我们想做的事!

例如,这将打印出所有被检测到的命名实体:

for entity in doc.ents: print(f"{entity.text} ({entity.label_})") ```

如果你运行了这段代码,你将得到一个关于文档中被检测出的命名实体及其类型的表:

伦敦 (GPE) 英格兰 (GPE) 英国 (GPE) 泰晤士河 (FAC) 大不列颠 (GPE) 伦敦 (GPE) 两千 (DATE) 罗马人 (NORP) 伦蒂尼恩 (PERSON)

你可以查看每个实体代码的含义。

需要注意的是,它误将“伦蒂尼恩”识别为人名而不是地名。这可能是因为在训练数据中没有与之相似的内容,但它做出了最佳猜测。如果你要解析具有专业术语的文本,命名实体的检测通常需要做一些微调。

让我们将这个实体检测的思想转换一下,做一个数据清理器。假设你正在尝试执行新的GDPR隐私条款,并且发现你所持有的上千个文档中都有个人身份信息,如姓名。现在你的任务是移除文档中的所有姓名。

如果手动移除上千个文档中的姓名,需要花费多年时间。但如果使用NLP,事情就简单多了。这是一个移除检测到的姓名的数据清理器:

```python import spacy

加载大规模英语NLP模型

nlp = spacy.load('encoreweb_lg')

如果检测到姓名,就用“REDACTED”替换

def replacenamewithplaceholder(token): if token.entiob != 0 and token.enttype == "PERSON": return "[REDACTED] " else: return token.string

依次解析文档中的所有实体并检测是否为姓名

def scrub(text): doc = nlp(text) for ent in doc.ents: ent.merge() tokens = map(replacenamewith_placeholder, doc) return "".join(tokens)

s = """在1950年,Alan Turing发表了著名文章《计算机器与智能》。在1957年,Noam Chomsky的《句法结构》以“普遍语法”为基础,革新了语言学,这是一种基于语法规则的系统。"""

print(scrub(s)) ```

如果你运行了这段代码,你会看到它如预期般工作:

在1950年,[REDACTED]发表了著名文章《计算机器与智能》。在1957年,[REDACTED]的《句法结构》以“普遍语法”为基础,革新了语言学,这是一种基于语法规则的系统。

信息提取

开箱即用的spaCy功能强大。但你也可以使用spaCy解析的输出作为更复杂的数据提取算法的输入。这里有一个名为textacy的Python库,它实现了多种基于spaCy的通用数据提取算法。这是一个良好的开端。

其中一个实现的算法是半结构化语句提取。我们用它来搜索解析树,查找主语是“伦敦”且动词是“be”形式的简单语句。这将帮助我们找到关于伦敦的信息。

来看看代码是怎样的:

```python import spacy import textacy.extract

加载大规模英语NLP模型

nlp = spacy.load('encoreweb_lg')

需要检测的文本

text = """伦敦是英格兰的首都,也是英国人口最多的城市。它位于泰晤士河边,已有两千年的主要居住历史。这座城市由罗马人建立,并被命名为伦蒂尼恩。"""

用spaCy解析文档

doc = nlp(text)

提取半结构化语句

statements = textacy.extract.semistructured_statements(doc, "伦敦")

打印结果

print("Here are the things I know about London:")

for statement in statements: subject, verb, fact = statement print(f"- {fact}") ```

它打印出了这些:

Here are the things I know about London: - 英格兰的首都,也是英国人口最多的城市。 - 两千年的主要居住历史。

也许这不会太令人印象深刻。但如果你将这段代码用于维基百科上关于伦敦的整篇文章,而不是仅仅三个句子,你将得到令人印象深刻的结果:

Here are the things I know about London: - 英格兰的首都,也是英国人口最多的城市。 - 两千年的主要居住历史。 - 世界上人口最多的城市,大约从1831年到1925年。 - 英格兰最大的城市。 - 易受洪水侵袭。 - 世界上最环保的城市之一,拥有超过40%的绿地或开放空间。 - 欧盟人口最多的城市,欧洲第二大城市。 - 世界上第19大都市,第18大都会区。 - 主要宗教为基督教,有许多教堂,尤其是在伦敦城。 - 还有重要的穆斯林、印度教徒、锡克教徒和犹太社区。 - 拥有42座印度教寺庙。 - 连续三年成为世界最贵的办公市场,根据2015年世界物业杂志报告。 - 作为国际金融中心之一,是最重要的金融地点。 - 作为旅游目的地,被TripAdvisor用户评为世界顶级城市。 - 作为主要国际航空运输枢纽,拥有世界上最繁忙的城市空域。 - 作为全国铁路网络的中心,70%的铁路旅行始于或结束于伦敦。 - 作为高等教育教学和研究中心,拥有欧洲最大的高等教育机构集中地。 - 家有Vivienne Westwood、Galliano、Stella McCartney、Manolo Blahnik和Jimmy Choo等设计师。 - 许多文学作品的背景。 - 电视制作的主要中心,包括BBC电视中心、The Fountain Studios和The London Studios。 - 也是流行音乐中心。 - 被称为“绿色城市”,拥有35000英亩的公共公园、森林和花园。 - 不是英格兰的首府,因为英格兰没有自己的政府。

现在事情变得有趣了起来!我们自动收集了大量的信息。

为了让事情更有趣,试着安装neuralcoref库,并添加共指解析到你的管道。这将为你提供更多信息,因为它会捕捉含有“它”的而不是直接表示“伦敦”的句子。

本文来源: 图灵汇 文章作者: 沙娜