计算机很擅长处理结构化的数据,比如工作表、数据库的表等。但我们人类的沟通通常使用词汇,而不是表。对于计算机来说,这是件很不幸的事情。
不幸的是,我们并没有生活在这个所有数据都是结构化的平行历史中。
这个世界中的许多信息都是非结构化的,比如英文文本,或任何其他人类语言。我们怎样才能让计算机理解非结构化的文字,并从中提取出数据呢?
自然语言处理(NaturalLanguageProcessing,简称NLP)是人工智能的一个子领域,它专注于让计算机理解并处理人类的语言。我们来看看NLP的工作原理,学学如何写一段Python程序从人类语言的文本中提取信息吧。
注意:如果你不关心NLP的工作原理,只希望复制粘贴代码,可以直接跳到“用Python编写NPL的流水线代码”一节。
计算机能理解人类语言吗?
自从计算机诞生以来,程序员们就在试图编写能理解英语等语言的程序。理由很明显,人类几千年来一直在用这些语言写东西,如果计算机能阅读并理解这些东西,那对人类非常有帮助。
计算机还不能真正地像人类那样理解英语,但它们已经能做得很好了!在某些特定的领域,NLP的能力已经像魔法一样了。在项目中使用NLP也许可以节省不少时间。
而且更好的是,NLP最新的进展可以很容易地通过开源的Python库访问到,如spaCy、textacy和neuralcoref等。你只需要写几行Python就可以。
从文本提取含义很困难
阅读并理解英语的过程非常复杂,这还没有考虑英语其实根本没有合乎逻辑并且一致的规则。比如,这个新闻标题是什么意思?
“Environmentalregulatorsgrillbusinessowneroverillegalcoalfires.”
规制者是在质问企业家关于非法烧煤的问题,还是规制者真的把企业家放在火上烧?可见,让计算机分析英语是非常复杂的。
让机器学习做任何复杂的事情通常意味着要建立一个流水线。其思想就是将问题分解成许多非常小的问题,然后用机器学习分别解决每个小问题。然后将几个机器学习模型连接起来让它们互相提供数据,就可以做非常复杂的事情。
这正是我们要在NLP上应用的策略。我们将把理解英语的整个过程分解成几个小步骤,看看每个步骤是怎样工作的。
一步步建立NLP流水线
我们来看一段来自维基百科的文本:
LondonisthecapitalandmostpopulouscityofEnglandandtheUnitedKingdom.StandingontheRiverThamesinthesoutheastoftheislandofGreatBritain,Londonhasbeenamajorsettlementfortwomillennia.ItwasfoundedbytheRomans,whonameditLondinium.(来源:维基百科条目“London”)
这段文字包含几个有用的内容。我们希望计算机阅读这段文本后能理解,伦敦是一个城市,伦敦位于英格兰,伦敦由罗马人建立等等。但为了达到这个目标,首先我们需要让计算机理解书面语言的最基本的概念。
第1步:句子分片
流水线的第一步就是将文本分解成独立的句子。我们可以得到:
1.“LondonisthecapitalandmostpopulouscityofEnglandandtheUnitedKingdom.”2.“StandingontheRiverThamesinthesoutheastoftheislandofGreatBritain,Londonhasbeenamajorsettlementfortwomillennia.”3.“ItwasfoundedbytheRomans,whonameditLondinium.”
我们可以假设每个英文句子都是独立的含义,写程序理解单个句子要比理解整个段落容易得多。
编写分句的模型非常容易,只需要在看到标点符号时进行分句即可。但现代的NLP流水线同时会用更复杂的技术,即使文档的格式不那么清晰也能正常分解。
第2步:将词汇变成标记(token)
现在我们已经把文档变成了句子,我们可以每次处理一个句子了。首先从文档的第一个句子开始:
“LondonisthecapitalandmostpopulouscityofEnglandandtheUnitedKingdom.”
流水线中的下一步是将这个句子分解成独立的单词,或者叫标记(token)。这一步叫做标记化(tokenization)。下面是结果:
“London”,“is”,“the”,“capital”,“and”,“most”,“populous”,“city”,“of”,“England”,“and”,“the”,“United”,“Kingdom”,“.”
对于英语来说标记化很容易,只需要利用空格将单词分隔开即可。我们还要把标点符号作为标记来处理,因为标点符号也是有意义的。
第3步:预测每个标记的词性
下一步,我们将查看每个标记,并猜测它的词性——是名词、动词、还是形容词?等等。弄清楚每个单词的角色能帮我们分析句子的含义。
我们可以把每个单词(以及它上下文环境中的一些单词)提供给已经训练好的词性分类模型:
词性模型是使用几百万个已经标注了每个单词词性的英语句子训练过的,它被训练成能够重复这种行为。
要注意这个模型完全是依据统计学的,它并不像人类那样理解每个单词的实际意义。它只知道怎样根据以前见过的类似句子来猜测词性。
在处理完整个句子之后,我们得到类似下面的结果:
有了这些信息,我们就可以提取一些最基本的含义了。例如,我们看到句子中的名词包含“London”和“capital”,所以这个句子很可能就是在讨论伦敦。
第4步:文本词形还原(lemmatization)
在英语(及大多数语言)中,单词会有不同的词形。例如下面两个句子:
Ihadapony.Ihadtwoponies.
两个句子都在谈论名词pony,但它们使用的是不同的变形。在使用计算机处理文本时,知道每个词的基本形很有帮助,这样可以知道两个句子讨论的是同一个概念。否则“pony”和“ponies”两个字符串会被计算机当作两个完全不同的单词。
在NLP中,这个过程叫做词形还原(lemmatization),即找出句子中每个单词的最基本词形(lemma)。
动词也有同样的问题。动词的词形还原可以找出它们的词根,即没有发生变化的形式。因此“Ihadtwoponies”将会变成“I[have]two[pony]”。
词性还原通常通过查找表的方式进行,根据它们的词性,在词形表中找出原形,可能还要加上一些特殊规则来处理一些没见过的词。
下面是经过词形还原,添加了词根形式之后的句子:
唯一的变化就是把“is”变成了“be”。
第5步:确定停止词
接下来,我们要考虑句子中每个单词的重要性。英语有许多出现频率非常高的填充词,如“and”、“the”和“a”等。在进行词频统计时,这些单词会引入许多噪声,因为它们出现的频率比其他单词高得多。一些NLP流水线会将这些词标记为停止词(stopwords),意思是在进行统计分析之前要过滤掉这些词。
将停止词标记成灰色后,我们的句子如下所示:
识别停止词只需要检查一个固定的已知停止词的词汇表即可。不过,没有能适用于所有应用的标准停止词列表。不同应用程序需要忽略的单词可能并不相同。
例如,如果你要建立一个摇滚乐队搜索引擎,你就不能忽略单词“The”。因为单词“The”不仅出现在许多乐队名称里,八十年代还有个著名的摇滚乐队就叫TheThe!
第6步:依赖解析
下一步是要找出句子中所有单词之间的关系。这一步叫做依赖解析(dependencyparsing)。
目标是建立一棵树,给句子中的每个单词找出一个唯一的父单词。树的根节点就是句子的主要动词。这里是句子的解析树最初的样子:
但我们还可以进一步。除了找出每个词的父单词之外,我们还能预测两个单词之间的关系类型:
这个解析树显示,句子的主语是名词“London”,它和“capital”是“be”关系。我们终于知道了些有用的东西——伦敦是首都!如果我们遍历句子的整个解析树(图中没有画出),我们甚至还能发现伦敦是英国的首都。
就像我们之前利用机器学习模型预测词性一样,依赖解析的原理也是将单词提供给一个机器学习模型,并计算出结果。但解析单词之间的依赖通常是个很复杂的任务,想要解释清楚其原理,那又是一整篇文章了。如果想知道它的工作原理,可以从MatthewHonnibal的这篇文章《ParsingEnglishinLinesofPython》(