如何批量训练 NLTK PunktSentenceTokenizer?

Jum*_*nMD 5 python nltk nltk-trainer

我正在尝试将财务文件拆分为句子。我有大约 50.000 个包含纯英文文本的文档。总文件大小约为 2.6 GB。

我将 NLTKPunktSentenceTokenizer与标准英文泡菜文件一起使用。我还通过提供额外的缩写对其进行了调整,但结果仍然不够准确。

由于 NLTK PunktSentenceTokenizer 基于 Kiss & Strunk (2006) 的无监督算法,我试图根据我的文档,基于nltk punkt 的训练数据格式来训练句子标记

import nltk.tokenize.punkt
import pickle
import codecs

tokenizer = nltk.tokenize.punkt.PunktSentenceTokenizer()
text = codecs.open("someplain.txt", "r", "utf8").read()
tokenizer.train(text)
out = open("someplain.pk", "wb")
pickle.dump(tokenizer, out)
out.close()
Run Code Online (Sandbox Code Playgroud)

不幸的是,在运行代码时,我收到一个错误,即内存不足。(主要是因为我首先将所有文件连接到一个大文件。)

现在我的问题是:

  1. 如何批量训练算法,这会导致较低的内存消耗吗?
  2. 我可以使用标准的英文泡菜文件并使用已经训练过的对象进行进一步训练吗?

我在 Core I7 2600K 和 16GB RAM 机器上的 Windows 10 上使用 Python 3.6 (Anaconda 5.2)。

Alb*_*ppi 2

我自己遇到这个问题后发现了这个问题。我想出了如何批量训练分词器,并将这个答案留给其他想要这样做的人。我能够PunktSentenceTokenizer在大约 12 小时内训练大约 200GB 的生物医学文本内容,每次内存占用不超过 20GB。尽管如此,我想赞同 @colidyre 的建议,PunktSentenceTokenizer在大多数情况下更喜欢其他工具。

您可以使用一个类以批量方式PunktTrainer进行训练。PunktSentenceTokenizer

from nltk.tokenize.punkt import PunktSentenceTokenizer, PunktTrainer
Run Code Online (Sandbox Code Playgroud)

假设我们有一个生成器,可以生成训练文本流

texts = text_stream()
Run Code Online (Sandbox Code Playgroud)

在我的例子中,生成器的每次迭代都会一次查询数据库中的 100,000 个文本,然后生成所有这些文本连接在一起。

我们可以实例化 aPunktTrainer然后开始训练

trainer = PunktTrainer()
for text in texts:
    trainer.train(text)
    trainer.freq_threshold()
Run Code Online (Sandbox Code Playgroud)

请注意处理每个文本后对该方法的调用freq_threshold。这通过清理有关不太可能影响未来训练的稀有标记的信息来减少内存占用。

完成后,调用 Finalize 训练方法。然后,您可以使用训练期间找到的参数实例化新的分词器。

trainer.finalize_training()
tokenizer = PunktSentenceTokenizer(trainer.get_params())
Run Code Online (Sandbox Code Playgroud)

@colidyre 建议使用 spaCy 并添加缩写。然而,提前知道哪些缩写将出现在您的文本域中可能很困难。为了获得两全其美的效果,您可以添加 Punkt 找到的缩写。您可以通过以下方式获得一组缩写

params = trainer.get_params()
abbreviations = params.abbrev_types
Run Code Online (Sandbox Code Playgroud)