在自然语言处理过程中,粉丝们经常会问:“尽管文本清理受任务的影响很大,但是否存在一些通用的清理流程,以及这些清理背后的逻辑?比如,是否需要替换URL、时间、货币、姓名、地名、数字等信息?”
本次,我们邀请到了Udacity无人驾驶课程的经理Aaron,为大家解答这个问题。
我们以英文文本处理为例,主要分为以下几个步骤:
标准化
获取纯文本文件后,第一步通常是进行标准化处理。在英语中,句子的首字母通常是大写的。有时全部大写是为了强调和区分风格。这对人类读者非常方便,但对于机器学习算法来说,'Car'、'car'和'CAR'是相同的词,机器无法区分。因此,通常会将文本中的所有字母统一转换成小写(通常是小写),以便每个词都有唯一的表示。
例如,如果将电影《The Second Renaissance》的一段影评存储在名为“文本”的变量中,并将其转换成小写,只需在Python中调用 lower() 方法即可。这是转换后的样子。注意更改的所有字母。其他语言可能有或没有对应的大小写,但根据NLP任务的不同,类似原理也可能适用。
你可能还想清除文本中的句号、问号、感叹号等特殊字符,只保留字母表中的字母和数字。对于文档分类和聚类等应用,正则表达式非常有效。这里可以匹配小写'a'至'z'、大写'A'至'Z'或者数字'0'到'9'范围之外的所有字符,并用空格代替。这样无需指定所有标点符号,也可以采用其他正则表达式。
小写转换和标点移除是两个最常见的文本标准化步骤。是否需要以及在哪个阶段使用这两个步骤取决于你的最终目标。
分词
Token是指具有一定意义且不可再分的符号。在英文自然语言处理中,Token通常是单独的词。因此,分词就是将每个句子拆分成一系列词。
通常最简单的方法是使用split()方法返回词列表。默认情况下,它是将一段话在空格字符处分割,包括空格、标签、新行等。这种方法还很智能,可以忽略序列中的多个空格字符,不会返回空字符串。你同样可以使用可选参数对其进行控制。目前我们只使用了Python的内置功能。当然,也可以使用工具箱,如NLTK,处理英文最常用的自然语言工具箱。在NLTK中,分词文本的最常见方法是使用nltk.tokenize中的word_tokenize()函数。这与split()执行的效果差不多,但更聪明一些。在尝试传入未标准化的原始文本时,根据标点符号位置的不同,对它们的处理也不同。
例如,头衔'Dr'后面的句号'.'与'Dr'保留在一起作为一个Token。可以想象,NLTK使用某种规则或模式决定如何处理每个标点符号。有时,我们可能需要将一段话分解成句子而不是单词。例如,如果你想翻译文本,可能需要将文本拆分成句子。这时,我们可以通过NLTK使用sent_tokenize()实现这一点。然后可以根据需要将每个句子拆分成词,NLTK提供了多种Token解析器,包括基于正则表达式的令牌解析器,可以用于一步清除标点符号并将其分词。
停用词移除
停用词是没有实际含义的词,如'is'/'our'/'the'/'in'/'at'等。它们不会给句子增加太多含义,但却是频率很高的词。为了减少要处理的词汇量,降低后续程序的复杂度,需要清除停用词。
在上述句子中,即使没有'are'和'the',我们仍能推断出人对狗的正面感情。你可以自行思考NLTK将英语中的哪些词作为停用词。这里,NLTK是基于特定的文本语料库或文本集。不同的语料库可能有不同的停用词。在一个应用中,某个词可能是停用词,而在另一个应用中这个词是有意义的词。要从文本中清除停用词,可以使用带过滤条件的Python列表理解。
在这里,我们将影评标准化和分词后清除其中的停用词。结果有些难以理解,但现在输入量缩小了很多,并保留了比较重要的词汇。
词性标注
还记得在学校学过的词性吗?名词、代词、动词、副词等。识别词在句子中的用途有助于更好地理解句子内容。此外,标注词性还可以明确词之间的关系,并识别出交叉引用。同样地,NLTK给我们带来了很多便利。你可以将词传入PoS tag函数。然后对每个词返回一个标签,并注明不同的词性。
这里函数正确地将出现的第一个'lie'标注为动词,将第二个标注为名词。关于标签含义的更多详细信息,请查阅NLTK文档。词性标注的一个典型应用是句子解析。例如,上图是NLTK手册中使用自定义语法解析歧义句的一个示例。实例中解析器返回了两种有效解释。我们也可以使用代码画出解析树,以便可以轻松地看出两者的区别。例如,“I shot an elephant in my pajamas”(“我穿着睡衣杀了一头象”)和“I shot an elephant in my pajamas”(“我杀了一头穿着我睡衣的象”)。
另外,还有其他许多方法可以进行PoS,比如Hidden Markov Models (HMM)以及Recurrent Neural Networks (RNNs)。
命名实体识别
命名实体通常是名词短语,用来指代某些特定的对象、人或地点。可以使用ne_chunk()方法标注文本中的命名实体。在进行这一步前,必须先进行分词并进行词性标注。
如图,这是一个非常简单的示例。NLTK还可以识别出不同的实体类型,分辨出人、组织和GPE(地缘政治实体)。此外,它还将'Udacity'和'Inc'这两个词识别成一个实体,效果不错。命名实体并不是所有情况都识别得很好,但如果对大型语料库进行训练,则非常有效。命名实体识别通常用于对新闻文章建立索引和进行搜索。我们可以搜索自己感兴趣的公司的相关新闻。
词干提取和词形还原
为了进一步简化文本数据,我们可以将词的不同变化和变形标准化。词干提取是将词还原成词干或词根的过程。
例如,'brancing'/'branched'/'branches'等都可以还原成'branch'。总而言之,它们都表达了分成多个路线或分支的含义。这有助于降低复杂度,并同时保留词所含的基本含义。词干提取是利用非常简单的搜索和替换样式规则进行的。
例如,后缀'ing'和'ed'可以丢弃;'ies'可以用'y'替换等。这样可能会变成不是完整词的词干,但只要这个词的所有形式都还原成同一个词干即可。因此,它们都含有共同的根本含义。
NLTK有几个不同的词干提取器可供选择,例如PorterStemmer()方法。上图例子中我们已经清除了停用词,所以部分转换效果非常好。例如,'started'还原成了'start'。但是像其它词,例如'people'末尾的'e'被删除,出现这样的原因是因为规则过于简单。
词形还原是将词还原成标准化形式的另一种技术。在这种情况下,转换过程实际上是利用词典,将一个词的不同变形映射到它的词根。通过这种方法,我们可以将较大的词形变化,如is/was/were还原成词根be。NLTK中的默认词形还原器使用nltk.stem.wordnet数据库将词还原成词根。
在这里我们试一下像词干提取一样,将WordNetLemmatizer()的实例初始化,并将各个词传入lemmatize()方法。结果中只有词'ones'被还原成了'one',其它词并无任何变化。仔细读各个词,你会发现'ones'是这里唯一的复数名词。实际上,这就是它被转换的原因。
词形还原需要知道每个词的词性。在这个例子中WordNetLemmatizer()默认词性是名词。但是我们可以指定PoS参数,修改这个默认设置。我们传入'v'代表动词。现在,两个动词形式'boring'和'started'都被转换了。
小结一下,在前面的示例中可以看出,词干提取有时会生成不是完整英语词的词干。词形还原与词干提取类似,差别在于最终形式也是有含义的词。也就是说,词形还原需要字典,而词干提取不需要字典。因此,根据你施加约束的不同,词干提取是对内存要求较低的方案。
总结
上文内容其实来自Udacity「自然语言处理工程师」的课程。总结一下典型英文自然语言处理工作流程。对于纯文本句子,首先将其转换成小写,并清除标点符号,将其标准化。然后用分词将其拆分成词,接下来可以清除停用词,以减少要处理的词汇量。根据应用的不同,可以选择同时进行词干提取和词形还原,将词还原成词根或词干。常见的方法是先进行词形还原,再进行词干提取。这个程序将自然语言句子转换成标准化记号序列,这样可以用于进一步分析。