第一部分:文本处理
欢迎来到机器学习和自然语言处理原型编码教程系列的第一部分。 Thoughtly正在制作一个着重于理解机器学习基础的系列教程,着重关注于在自然语言处理中的应用。
这一系列教程的目标是提供有据可查的可用代码,附加留言部分的深入探讨。代码将被放到GitHub上,在一个开放的许可证下,允许你任意修改或使用——不必署名(注明来源)。这里的代码为了明白起见以牺牲性能为代价写的比较冗长。如果你有大量的数据要处理,这些工具的可扩展性很可能无法达到完成你目的的要求。幸运的是,我们正在计划通过研究此处讨论的算法在当下最新的实现,来更好地对这个系列进行深入探索。这些内容都是黑盒子,是我们在初始系列中有意避免(到实用的程度)提到的内容。我们相信,在能使用这些黑盒子之前,在机器学习方面打下一个坚实的基础是至关重要的。
第一部分的重点是如何从文本语料库提取出信息来。我们有意用介绍性的水平来开始教程,但是它涉及到很多不同的技巧和测量标准,这些方法都会在之后应用到更深入的机器学习任务上。
文本提取
下文介绍的以及此处代码中用到的工具,都假设我们将所选的语料当作一袋单词。这是你在处理文本文档的时候常常会看到的一个基本概念。将语料当作一袋单词是将文档向量化中的一个典型步骤,以供机器学习算法进一步处理。把文档转换成可处理向量通常还需要采取一些额外步骤,我们将在后面的课程中对此进行讨论。本课程中介绍的概念和工具将作为后面工具的构建模块。也许更重要的是,这些工具可以帮助你通过快速检查一个文本语料库,从而对它所包含的内容有一个基本的了解。
本课程中我们所研究的代码及示例都是使用Python实现的。这些代码能够从NLTK(Python的自然语言工具包)所提供的不同的文本语料库中提取数据。这是个包括了ABC新闻的文字、圣经的创世纪、从古滕堡计划中选取的部分文本、总统就职演说、国情咨文和从网络上截取的部分文本所组成的语料库。另外,用户还能从他们自己提供的语料库来提取文本。从NLTK导入的代码并不是特别有趣,但我们想指出的是,要从NLTK文本语料库中提取数据是非常简单方便的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
def load_text_corpus(args): if args["abc"]: logging.debug("Loading the ABC corpus.") name = "ABC" words = nltk.corpus.abc.words() elif args["genesis"]: logging.debug("Loading the ABC corpus.") name = "Genesis" words = nltk.corpus.genesis.words() elif args["gutenberg"]: logging.debug("Loading the Gutenberg corpus.") name = "Gutenberg" words = nltk.corpus.gutenberg.words() elif args["inaugural"]: logging.debug("Loading the Inaugural Address corpus.") name = "Inaugural" words = nltk.corpus.inaugural.words() elif args["stateUnion"]: logging.debug("Loading the State of the Union corpus.") name = "Union" words = nltk.corpus.state_union.words() elif args["webtext"]: logging.debug("Loading the webtext corpus.") name = "Web" words = nltk.corpus.webtext.words() elif args["custom"] != None: logging.debug("Loading a custom corpus from " + args["custom"]) name = "Custom" words = load_custom_corpus(args["custom"]) else: words = "" name = "None" logging.debug("Read " + str(len(words)) + " words: " + str(words[0:20])) return words, name |
上面的大部分代码只是日志。有意思的部分在357行、362行、367行等。基于用户选择,每部分加载不同的语料库。 NLTK对从现有语料库中提取文本提供了一些非常便利的方法。这包括一些简单的、纯文本的语料库,也包括一些已经用各种方式被标记过的语料库 —— 语料库中的每个文档可能被标记过类别或是语料库中有的语音已被加过标签,如此等等。在本课程中,我们对NLTK的使用仅限于语料库的导入、词汇的切分,以及我们下面将讨论两个操作,词根和词形还原。虽然不会总是如此,但现在为止足够我们需要的所有功能。值得注意的是,您还可以在脚本中使用-custom参数导入自定义语料库。这应该是含有.txt文件的文件夹。该文件夹是递归读入的,所以含有.txt文件的子文件夹也能被处理。
词汇切分
词汇切分是切分语料库,使之变成各个独立部分——通常指单词,的行为。我们这样做是因为大多数ML算法无法处理任意长的文本字符串。相反,他们会假设你已经分割你的语料库为单独的,算法可处理的词块(token)。虽然我们将在后面的课程详细讨论这个话题,算法不一定限于一次只处理一个词块(token)。事实上,许多算法只在处理短序列(n-grams)时有用。本课程中我们将情况限定于一序列(1-grams),或者叫,单序列(unigram)。
对文本语料库做词汇切分的最简单的方法就是仅基于空白字符。这种方法确实非常简单,但它也有缺点。例如,它会导致位于句尾的文本包含有句尾标点符号,而一般不需要这样。在另一方面,类似can’t和e.g.这样带有词内标点的单词就没法被正确提取出来了。我们可以添加一步操作来删除所有非字母数字的字符。这将解决句尾标点符号的问题,同时也能将can’t和e.g.这样的单词提取出来,尽管是以丢掉了他们的标点符号的方式被提取出来的。然而,这也引入了一个新的问题。对于某些应用,我们还是希望保留标点符号。在创建语言模型的时候,句尾标点能区分一个单词是否是结尾单词,从这方面来说,额外的标点信息是有价值的。
对于这个任务,我们要将一些标点符号(句号)作为一个词,使用NLTK word_tokenizer(它是基于TreebankWordTokenizer来实现的)来做词汇切分。这个分词器有很多针对各式各样的词汇做切分的规则。举例来说,“can’t”这样的缩写实际上被分成了两个词(token) – ca和n’t。有趣的是,这意味着我们最后会得到ca这样的词,它理想地匹配了can(在某些任务中)。这样的错误匹配是这种符号化算法带来的不幸后果。NLTK支持多种分词器。这是一个及其冗长的文件,http://www.nltk.org/api/nltk.tokenize.html,但在里面可以找到它所支持的分词器的细节。
词干提取和词形还原
一旦取到了文字我们就可以开始处理它。脚本提供了许多简单的工具,它们会帮助我们查看我们所选择的内容。之后我们会深入谈到这些工具。首先,让我们思考一下该用什么方法来操作我们取到的文本。通常我们需要为ML算法提供从语料库提取的原始文本词汇(单词)。在其他情况下,将这些单词转成原始内容的各种变形也是有道理的。
具体来说,我们经常要将原始单词截断到它的词根。那么,什么是一个词根呢?英语单词有从原始单词延伸出的通用后缀。就拿单词”run”为例。有很多的扩展它的词 – “runner”,”runs”,”running”等,即对基本定义的进一步阐述。词干提取是从”runner”,”runs”以及“running”中去除所有和”run”不一致的部分的过程。请注意,在上述列表中不包含”ran” —— 后面我们再对此进行阐述。下面是一个被提取词干的句子的具体实例。
1 |
stem(Jim is running to work.) => Jim is run to work. |
我们已经丢失了”吉姆在跑步”这个信息,尽管此处的上下文隐含的所有其他信息都说不通。我们不可能完全扭转这一点 —— 我们可以猜测那里曾经是什么词,但我们很可能会弄错。
此处提供的代码可以让你对你的语料库进行词干提取。实际的词干提取是微不足道的,因为我们会使用NLTK来进行这部分工作。我们只需通过输入数组迭代,并返回使用NLTK Porter Stemmer所得到的各种提取后的词干变体。有许多不同的词干分析器可供选择,还包括非英语语言的选项。Porter Stemmer常用于英语。
1 2 3 4 5 6 7 |
def stem_words_array(words_array): stemmer = nltk.PorterStemmer(); stemmed_words_array = []; for word in words_array: stem = stemmer.stem(word); 译组。 第一部分:文本处理 欢迎来到机器学习和自然语言处理原型编码教程系列的第一部分。 Thoughtly正在制作一个着重于理解机器学习基础的系列教程,着重关注于在自然语言处理中的应用。 这一系列教程的目标是提供有据可查的可用代码,附加留言部分的深入探讨。代码将被放到GitHub上,在一个开放的许可证下,允许你任意修改或使用——不必署名(注明来源)。这里的代码为了明白起见以牺牲性能为代价写的比较冗长。如果你有大量的数据要处理,这些工具的可扩展性很可能无法达到完成你目的的要求。幸运的是,我们正在计划通过研究此处讨论的算法在当下最新的实现,来更好地对这个系列进行深入探索。这些内容都是黑盒子,是我们在初始系列中有意避免(到实用的程度)提到的内容。我们相信,在能使用这些黑盒子之前,在机器学习方面打下一个坚实的基础是至关重要的。 第一部分的重点是如何从文本语料库提取出信息来。我们有意用介绍性的水平来开始教程,但是它涉及到很多不同的技巧和测量标准,这些方法都会在之后应用到更深入的机器学习任务上。 文本提取下文介绍的以及此处代码中用到的工具,都假设我们将所选的语料当作一袋单词。这是你在处理文本文档的时候常常会看到的一个基本概念。将语料当作一袋单词是将文档向量化中的一个典型步骤,以供机器学习算法进一步处理。把文档转换成可处理向量通常还需要采取一些额外步骤,我们将在后面的课程中对此进行讨论。本课程中介绍的概念和工具将作为后面工具的构建模块。也许更重要的是,这些工具可以帮助你通过快速检查一个文本语料库,从而对它所包含的内容有一个基本的了解。 本课程中我们所研究的代码及示例都是使用Python实现的。这些代码能够从NLTK(Python的自然语言工具包)所提供的不同的文本语料库中提取数据。这是个包括了ABC新闻的文字、圣经的创世纪、从古滕堡计划中选取的部分文本、总统就职演说、国情咨文和从网络上截取的部分文本所组成的语料库。另外,用户还能从他们自己提供的语料库来提取文本。从NLTK导入的代码并不是特别有趣,但我们想指出的是,要从NLTK文本语料库中提取数据是非常简单方便的。
上面的大部分代码只是日志。有意思的部分在357行、362行、367行等。基于用户选择,每部分加载不同的语料库。 NLTK对从现有语料库中提取文本提供了一些非常便利的方法。这包括一些简单的、纯文本的语料库,也包括一些已经用各种方式被标记过的语料库 —— 语料库中的每个文档可能被标记过类别或是语料库中有的语音已被加过标签,如此等等。在本课程中,我们对NLTK的使用仅限于语料库的导入、词汇的切分,以及我们下面将讨论两个操作,词根和词形还原。虽然不会总是如此,但现在为止足够我们需要的所有功能。值得注意的是,您还可以在脚本中使用-custom参数导入自定义语料库。这应该是含有.txt文件的文件夹。该文件夹是递归读入的,所以含有.txt文件的子文件夹也能被处理。 词汇切分词汇切分是切分语料库,使之变成各个独立部分——通常指单词,的行为。我们这样做是因为大多数ML算法无法处理任意长的文本字符串。相反,他们会假设你已经分割你的语料库为单独的,算法可处理的词块(token)。虽然我们将在后面的课程详细讨论这个话题,算法不一定限于一次只处理一个词块(token)。事实上,许多算法只在处理短序列(n-grams)时有用。本课程中我们将情况限定于一序列(1-grams),或者叫,单序列(unigram)。 对文本语料库做词汇切分的最简单的方法就是仅基于空白字符。这种方法确实非常简单,但它也有缺点。例如,它会导致位于句尾的文本包含有句尾标点符号,而一般不需要这样。在另一方面,类似can’t和e.g.这样带有词内标点的单词就没法被正确提取出来了。我们可以添加一步操作来删除所有非字母数字的字符。这将解决句尾标点符号的问题,同时也能将can’t和e.g.这样的单词提取出来,尽管是以丢掉了他们的标点符号的方式被提取出来的。然而,这也引入了一个新的问题。对于某些应用,我们还是希望保留标点符号。在创建语言模型的时候,句尾标点能区分一个单词是否是结尾单词,从这方面来说,额外的标点信息是有价值的。 对于这个任务,我们要将一些标点符号(句号)作为一个词,使用NLTK word_tokenizer(它是基于TreebankWordTokenizer来实现的)来做词汇切分。这个分词器有很多针对各式各样的词汇做切分的规则。举例来说,“can’t”这样的缩写实际上被分成了两个词(token) – ca和n’t。有趣的是,这意味着我们最后会得到ca这样的词,它理想地匹配了can(在某些任务中)。这样的错误匹配是这种符号化算法带来的不幸后果。NLTK支持多种分词器。这是一个及其冗长的文件,http://www.nltk.org/api/nltk.tokenize.html,但在里面可以找到它所支持的分词器的细节。 词干提取和词形还原一旦取到了文字我们就可以开始处理它。脚本提供了许多简单的工具,它们会帮助我们查看我们所选择的内容。之后我们会深入谈到这些工具。首先,让我们思考一下该用什么方法来操作我们取到的文本。通常我们需要为ML算法提供从语料库提取的原始文本词汇(单词)。在其他情况下,将这些单词转成原始内容的各种变形也是有道理的。 具体来说,我们经常要将原始单词截断到它的词根。那么,什么是一个词根呢?英语单词有从原始单词延伸出的通用后缀。就拿单词”run”为例。有很多的扩展它的词 – “runner”,”runs”,”running”等,即对基本定义的进一步阐述。词干提取是从”runner”,”runs”以及“running”中去除所有和”run”不一致的部分的过程。请注意,在上述列表中不包含”ran” —— 后面我们再对此进行阐述。下面是一个被提取词干的句子的具体实例。
我们已经丢失了”吉姆在跑步”这个信息,尽管此处的上下文隐含的所有其他信息都说不通。我们不可能完全扭转这一点 —— 我们可以猜测那里曾经是什么词,但我们很可能会弄错。 此处提供的代码可以让你对你的语料库进行词干提取。实际的词干提取是微不足道的,因为我们会使用NLTK来进行这部分工作。我们只需通过输入数组迭代,并返回使用NLTK Porter Stemmer所得到的各种提取后的词干变体。有许多不同的词干分析器可供选择,还包括非英语语言的选项。Porter Stemmer常用于英语。
|