新智元推荐
来源:Medium
作者:Adam Geitgey
编译:Bot、三石
【新智元导读】自然语言处理是AI的一个子领域,从人们日常沟通所用的非结构化文本信息中提取结构化数据,以便计算机理解。本文用通俗易懂的语言深入浅出的介绍了自然语言处理,并用Python实现了几个非常有趣的实例。
自然语言处理(NLP)是人工智能的一个子领域,它专注于使计算机能够理解和处理人类语言。本文会介绍NLP工作的基本机制,希望读者能从中得到启发。
注:本文选用的示例语言是英语。
自计算机诞生之初,程序员们就一直在尝试编写能理解语言的程序。原因很简单——人类使用语言的历史已长达千年,如果计算机能阅读并理解所有数据,这将大有裨益。
虽然现在计算机还不能像人类一样真正读懂语言,但它们确实取得了不少进展,在某些领域,使用NLP可以为事物带来神奇的改变。通过把NLP技术应用于你自己的项目,也许你会因此节约大量时间。
更好的消息是,现在我们可以通过开源Python库(如spaCy、textacy和neuralcoref)轻松访问NLP领域的最新成果。只需几行代码,令人惊叹的成果立马实现。
阅读和理解语言是一个非常复杂的过程——它们甚至不会判断这样的理解是否符合逻辑和一致性。例如,下面这个新闻标题表达了什么含义?
“Environmental regulators grill business owner over illegal coal fires.” 环境监管机构就非法燃煤一事___企业主。(grill:追问,炙烤)
监管机构是在质疑企业存在非法燃煤情况,还是在拿企业主做饭?如你所见,用计算机解析语言会让问题变得很复杂。
在机器学习中,解决复杂任务通常意味着建立一个pipeline。它的想法是把问题分解成若干个非常小的部分,然后用机器学习去一一破解,最后,通过将这些机器学习模型拼接在一起,我们可以用它完成复杂任务。
而这正是我们在NLP中常用的策略。我们把理解语言文本这个过程分成几个小块,然后独立推敲它们的具体理解方式。
下面是维基百科中关于“伦敦”的一段文字:
London is the capital and most populous city of England and the United Kingdom. Standing on the River Thames in the south east of the island of Great Britain, London has been a major settlement for two millennia. It was founded by the Romans, who named it Londinium. 伦敦是英格兰和英国的首府,也是英国人口最多的城市。它位于大不列颠岛东南部的泰晤士河畔,2000年来一直是这一地区的主要定居点之一。伦敦最初由罗马人建立,取名为伦蒂尼恩。
这段文字包含多个有用事实,如果计算机能从中读懂“伦敦是一座城市”“伦敦位于英格兰”“伦敦由罗马人建立”,那就大功告成了。但为了实现这一目标,我们首先要向计算机传授书面语言的最基本概念,然后再谋求进一步发展。
第一步:语句分割(Sentence Segmentation)
NLP pipeline的第一步是先把文本分割成单独的句子,如下所示:
伦敦是英格兰和英国的首府,也是英国人口最多的城市。
它位于大不列颠岛东南部的泰晤士河畔,2000年来一直是这一地区主要的定居点之一。
伦敦最初由罗马人建立,取名为伦蒂尼恩。
我们可以假设这里的每个句子都表示一种独立的思想或想法,比起理解整个段落,编写程序来理解单个句子确实会容易得多。
至于构建语句分割模型,这不是一件难事,我们可以根据标点符号确定每个句子。当然,现代NLP通常会用更复杂的技术,即便文档内容不整洁,它还是能大致区分完整句子。
第二步:单词词例(Word Tokenization)
有了一个个被拆分的句子,现在我们可以对它们进行逐一处理。让我们从第一句开始:
London is the capital and most populous city of England and the United Kingdom.
这一步的目标是把句子再分割成单独的单词或标点符号,分割完成后,整个句子变成了这样:
“London”, “is”, “ the”, “capital”, “and”, “most”, “populous”, “city”, “of”, “England”, “and”, “the”, “United”, “Kingdom”, “.”
英语中存在自然分界符——空格,所以对它生成词例非常方便。只要两个词例之间有空格,我们就可以把它们直接分开。因为标点符号也有意义,我们要把它们视为单独的词例。
第三步:预测词例词性
接下来,我们来关注词例的词性:名词、动词、形容词……知道每个词语在句子中的作用有助于我们理解句子在说什么。
要实现这一点,我们可以事先训练一个词性分类模型,然后把每个单词输入其中预测词性:
这个模型最初是在数百万个英语句子上训练的,数据集中已经标明每个单词的词性,因此它可以学会这个“定义”的过程。但是注意一点,这个模型完全是基于统计数据的——它实际上无法像人类那样理解单词含义,而是只能根据“看”到过的类似句子进行猜测。
处理完整句后,我们会得到这样的结果:
有了这些信息,我们就可以开始收集一些非常基本的含义,比如句子中的名词包括“伦敦”“首府”,所以这句话有大概率是在谈论伦敦。
第四步:文本词形还原(Text Lemmatization)
在英语中,单词是有不同形式的,比如:
I had a pony.
I had two ponies.
两个句子都涉及名词pony(小马),但一个是单数形式,一个是复数形式。当计算机在处理文本时,如果没有说明,它会把“pony”和“ponies”看成完全不同的对象,因此了解每个单词的基本形式很有帮助,只有这样,计算机才知道两个句子在谈论同一个概念。
在NLP中,我们把这种将一个任何形式的语言词汇还原为一般形式的过程称为词形还原,它能找出句子中每个单词的最基本形式。
同样的,这也适用于英语动词。我们可以用词形还原找出单词词根,这之后,“I had two ponies”就变成了“I [have] two [pony]”。
词形还原是通过检索词汇生成表格实现的,它也有可能具有一些自定义规则,可以处理人们从未见过的单词。
以下是经还原的例句,我们做的唯一改变是把“is”变成“be”:
第五步:识别停用词(Identifying Stop Words)
然后就是衡量句子中每个单词的重要性。英语中有很多填充词,比如经常出现的“and”“the”和“a”。在对文本进行统计时,这些词会引入很多噪音,因为它们出现的频率很高。一些NLP pipeline会将它们标记为停用词 ——也就是说,在进行任何统计分析之前,我们可能会希望过滤掉这些词。
下面是标灰停用词的例句:
停用词检测也有一个事先准备好的列表,但它和词形还原有区别,我们没有适用于任何问题的标准停用词列表,它需要具体问题具体分析。比方说,如果我们要构建一个有关摇滚乐队的搜索引擎,那“The”这个词千万不能被忽略,因为它会出现在很多乐队的名字里,20世纪80年代还有一支著名的乐队叫“The The”。
第六步(a):依存句法分析(Dependency Parsing)
下一步是弄清楚句子中的所有单词是如何相互关联的,也就是依存句法分析。
我们的目标是构建一棵依存树,其中树根处是占据支配地位的主要动词,简称主词,处于依存地位的是从词:
但我们可以更进一步。除了识别每个单词的主词外,我们还可以预测这两个单词之间的依存关系类型:
这棵依存树告诉我们句子的主语是“London”,它和“capital”存在一个“be”的关系。据此我们得到了一条有用信息——London is a capital。在这个基础上,如果我们继续往后看,可以发现,其实London is the capital of the United Kingdom。
就像我们之前使用机器学习模型预测词性一样,依存句法分析也可以用一个模型来实现。不同的是,解析单词依存特别复杂,需要结合整篇文章详细解释。如果你感兴趣,Matthew Honnibal的“用500行Python代码解析英语”是个不错的教程。
虽然2015年的时候,作者表示这种方法已经成为标准,但放到现在来看,它还是有点过时,很多研究人员都已经不再用它了。2016年,Google发布了一个名为Parsey McParseface的新依存解析器,它基于深度学习,在性能上明显超出已有基准,因此一经发布就被广泛传播。一年后,他们又发布了更新版本ParseySaurus,进一步做了提升。简而言之,依存句法分析现在还是一个活跃的研究领域,并且在不断变化和改进。
此外,许多英语句子存在意义含糊不清的问题,往往难以解析。在这些情况下,模型会基于句子的各个解析版本猜测一个可能性最高的选择,但它并不完美,有时模型会出现令人尴尬的错误。但随着时间的推移,我们的NLP模型会逐渐走向合理。
第六步(b):寻找名词短语
到目前为止,我们已经把句子中的每个单词视为一个单独的实体,但有时这些表示单个想法或事物的词组合在一起会更有意义。利用依存树,我们可以自动整合信息,把讨论同一个事物的单词组合在一起。
比起下图这个形式:
我们可以对名词短语进行分组以生成:
是否要采取这一步骤取决于我们的最终目标。但是,如果我们不需要了解句子的额外细节,比如哪些词是形容词,而是更多地关注提取完整想法,那么这通常是简化句子的一个便捷方法。
第七步:命名实体识别(NER)
完成上述步骤后,我们就可以摆脱初级语法,开始真正着手提取意义。
在示例句子中,我们有以下名词:
这些名词中包含一些现实存在的东西,比如“伦敦”“英格兰”“英国”表示地图上的某个地理位置。有了这些信息,我们就可以使用NLP自动提取文档中提到的真实世界的位置列表。
命名实体识别(NER)的目标是检测这些表示现实世界食物的词,并对它们进行标记。下图把各个词例输入NER模型后,示例句子的变化情况:
虽然直观上看不出,但NER绝不是简单地查词典、打标签,它包含一个单词在上下文中位置的统计模型,可以预测不同单词分别代表哪种类型的名词。举个例子,一个好的NER模型可以区分“Brooklyn”是表示人名Brooklyn Decker,还是地名布鲁克林。
以下是典型NER系统可以标记的一些对象:
人的名字
公司名称
地理位置(地缘和政治)
产品名称
日期和时间
金额
事件名称
NER有很多用途,因为它可以轻易从文本中获取结构化数据,这是快速从NLP pipeline中获取有价值信息的最简单的方法之一。
第八步:共指消解
截至目前,我们已经有了许多和句子相关的有用表征。我们知道每个单词的词性、单词间的依存关系,以及那些词表示命名实体。
但我们还有一个棘手的问题,就是英语中包含大量代词,比如“he”“she”“it”,这些词频繁出现在句子里,是我们为了避免重复提及某个名称而使用的简称。人类可以根据上下文理解这些代词的含义,但NLP模型不行,因为到目前为止,它只是一句一句地检测。
让我们来看示例的第三句:
“It was founded by the Romans, who named it Londinium.”
根据NLP pipeline,我们的模型只知道“it”是罗马人造的,还不知道“it”是什么。但这个问题想必难不倒任何读得动这段话的人,我们知道这里的“it”就是第一句里的“London”。
以下是在我们的文档中为“伦敦”一词运行共识解析的结果:
通过将共指消解与依存树、命名实体信息相结合,我们可以从该文档中提取大量信息!事实上,这也是现在NLP领域的一大难点,它的难度远高于单个句子解析。虽然近年来基于深度学习最新进展的某些成果已经取得了一定突破,但它们都不完美。
以上是关于NLP的一些基础知识,如果你对这个内容感兴趣,以后我们还会讨论NLP的更多内容,如文本分类、智能助理解析问题等具体应用。
下图是完整的NLP Pipeline概述:
Coreference resolution是一个可选的步骤
首先,假设你已经安装了Python3,那么按着下面的代码可以安装spaCy:
# Install spaCy
pip3 install -U spacy
# Download the large English model for spaCy
python3 -m spacy download en_core_web_lg
# Install textacy which will also be useful
pip3 install -U textacy
然后编写如下代码来运行NLP Pipeline:
import spacy
# Load the large English NLP model
nlp = spacy.load('en_core_web_lg')
# The text we want to examine
text = """London is the capital and most populous city of England and
the United Kingdom. Standing on the River Thames in the south east
of the island of Great Britain, London has been a major settlement
for two millennia. It was founded by the Romans, who named it Londinium.
"""
# Parse the text with spaCy. This runs the entire pipeline.
doc = nlp(text)
# 'doc' now contains a parsed version of text. We can use it to do anything we want!
# For example, this will print out all the named entities that were detected:
for entity in doc.ents:
print(f"{entity.text} ({entity.label_})")
运行过后,你将得到从文档中检测到的命名实体和实体类型的列表:
London (GPE)
England (GPE)
the United Kingdom (GPE)
the River Thames (FAC)
Great Britain (GPE)
London (GPE)
two millennia (DATE)
Romans (NORP)
Londinium (PERSON)
值得注意的是,在“Londinium”上出现了一个错误,认为它是一个人的名字,而不是一个地方。这可能是因为在训练数据集中没有类似的东西,它做出了最好的猜测。命名实体检测(Named Entity Detection)通常需要进行一些模型微调。
此处,让我们考虑一下检测实体,并将其扭转以构建数据清理器。对数千个文档手动编辑其名称可能需要好几年的时间,但对于NLP来说,这简直就是小菜一碟。如下是一个简单的数据清理器,它可以删除检测到的所有名称:
import spacy
# Load the large English NLP model
nlp = spacy.load('en_core_web_lg')
# Replace a token with "REDACTED" if it is a name
def replace_name_with_placeholder(token):
if token.ent_iob != 0 and token.ent_type_ == "PERSON":
return "[REDACTED] "
else:
return token.string
# Loop through all the entities in a document and check if they are names
def scrub(text):
doc = nlp(text)
for ent in doc.ents:
ent.merge()
tokens = map(replace_name_with_placeholder, doc)
return "".join(tokens)
s = """
In 1950, Alan Turing published his famous article "Computing Machinery and Intelligence". In 1957, Noam Chomsky’s
Syntactic Structures revolutionized Linguistics with 'universal grammar', a rule based system of syntactic structures.
"""
print(scrub(s))
其运行结果如下:
In 1950, [REDACTED] published his famous article "Computing Machinery and Intelligence". In 1957, [REDACTED]
Syntactic Structures revolutionized Linguistics with 'universal grammar', a rule based system of syntactic structures.
有一个名为textacy的python库,它在spaCy的基础上实现了几种常见的数据提取算法。它实现的一个算法叫做半结构化语句提取( Semi-structured Statement Extraction)。我们可以用它来对简单的语句搜索解析树,其中主语是“London”,而动词是“be”的一种形式。这有助于我们找到有关伦敦的fact。如下所示:
import spacy
import textacy.extract
# Load the large English NLP model
nlp = spacy.load('en_core_web_lg')
# The text we want to examine
text = """London is the capital and most populous city of England and the United Kingdom.
Standing on the River Thames in the south east of the island of Great Britain,
London has been a major settlement for two millennia. It was founded by the Romans,
who named it Londinium.
"""
# Parse the document with spaCy
doc = nlp(text)
# Extract semi-structured statements
statements = textacy.extract.semistructured_statements(doc, "London")
# Print the results
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:
- the capital and most populous city of England and the United Kingdom.
- a major settlement for two millennia.
这看起来可能很简单,但如果你在整个伦敦维基百科的文章文本上运行同样的代码(而不是仅仅用三句话),你会得到令人印象深刻的结果,如下所示:
Here are the things I know about London:
- the capital and most populous city of England and the United Kingdom
- a major settlement for two millennia
- the world's most populous city from around 1831 to 1925
- beyond all comparison the largest town in England
- still very compact
- the world's largest city from about 1831 to 1925
- the seat of the Government of the United Kingdom
- vulnerable to flooding
- "one of the World's Greenest Cities" with more than 40 percent green space or open water
- the most populous city and metropolitan area of the European Union and the second most populous in Europe
- the 19th largest city and the 18th largest metropolitan region in the world
- Christian, and has a large number of churches, particularly in the City of London
- also home to sizeable Muslim, Hindu, Sikh, and Jewish communities
- also home to 42 Hindu temples
- the world's most expensive office market for the last three years according to world property journal (2015) report
- one of the pre-eminent financial centres of the world as the most important location for international finance
- the world top city destination as ranked by TripAdvisor users
- a major international air transport hub with the busiest city airspace in the world
- the centre of the National Rail network, with 70 percent of rail journeys starting or ending in London
- a major global centre of higher education teaching and research and has the largest concentration of higher education institutes in Europe
- home to designers Vivienne Westwood, Galliano, Stella McCartney, Manolo Blahnik, and Jimmy Choo, among others
- the setting for many works of literature
- a major centre for television production, with studios including BBC Television Centre, The Fountain Studios and The London Studios
- also a centre for urban music
- the "greenest city" in Europe with 35,000 acres of public parks, woodlands and gardens
- not the capital of England, as England does not have its own government
通过spaCy文档和textacy文档,你将看到大量使用解析文本的示例。接下来看一下另外一个实例:假设你在搭建一个网站,如果你的网站中有搜索栏目,你肯定是希望能够像谷歌那样自动完成常见搜索查询,如下图所示:
谷歌对“London”一词的文本查询自动补全
若要做到这点,我们需要一个列表来为用户提供建议。可以使用NLP快速生成这些数据。下面是一种从文档中提取经常提到的名词块的方法:
import spacy
import textacy.extract
# Load the large English NLP model
nlp = spacy.load('en_core_web_lg')
# The text we want to examine
text = """London is [.. shortened for space ..]"""
# Parse the document with spaCy
doc = nlp(text)
# Extract noun chunks that appear
noun_chunks = textacy.extract.noun_chunks(doc, min_freq=3)
# Convert noun chunks to lowercase strings
noun_chunks = map(str, noun_chunks)
noun_chunks = map(str.lower, noun_chunks)
# Print out any nouns that are at least 2 words long
for noun_chunk in set(noun_chunks):
if len(noun_chunk.split(" ")) > 1:
print(noun_chunk)
如果你在London的维基百科中运行这个代码,将得到如下结果:
westminster abbey
natural history museum
west end
east end
st paul's cathedral
royal albert hall
london underground
great fire
british museum
london eye
.... etc ....
本文理论部分经授权转载自微信公众号“论智”(ID:jqr_AI)
新智元AI WORLD 2018大会【早鸟票】
开售!
新智元将于9月20日在北京国家会议中心举办AI WORLD 2018 大会,邀请机器学习教父、CMU教授 Tom Mitchell,迈克思·泰格马克,周志华,陶大程,陈怡然等AI领袖一起关注机器智能与人类命运。
大会官网:
http://www.aiworld2018.com/
即日起到8月19日,新智元限量发售若干早鸟票,与全球AI领袖近距离交流,见证全球人工智能产业跨越发展。
活动行购票链接:
http://www.huodongxing.com/event/6449053775000
活动行购票二维码: