从巨大的文本中提取 n 克

Posted

技术标签:

【中文标题】从巨大的文本中提取 n 克【英文标题】:extracting n grams from huge text 【发布时间】:2015-06-05 21:59:07 【问题描述】:

例如我们有以下文本:

“Spark 是一个用于编写快速、分布式程序的框架。Spark 解决了与 Hadoop MapReduce 类似的问题,但速度快 内存中的方法和干净的函数式 API。 ……”

我需要这个文本的所有可能的部分,一个词一个词,然后两个两个,三个三个到五个到五个。 像这样:

ones : ['Spark', 'is', 'a', 'framework', 'for', 'writing, 'fast', “分布式”、“程序”、...]

twos : ['Spark is', 'is a', 'a framework', 'framework for', 'for writing' ...]

threes : ['Spark is a', 'is a framework', 'a framework for', '写作框架','快速写作',...]

。 . .

fives : ['Spark 是一个框架', '是一个写作框架', '一个用于快速编写的框架','用于编写快速分布式的框架',...]

请注意,要处理的文本是巨大的文本(大约 100GB)。 我需要这个过程的最佳解决方案。应该是多线程并行处理吧。

我不需要一次完整的列表,它可以流式传输。

【问题讨论】:

您意识到这将生成的潜在短语数量非常庞大,可能达到数万亿,对吗? 我能想到的最好的方法是加载一次内容,然后slice 他们,因为您需要一次创建整个列表,因此您可能不需要阅读一些技术一行一行。 @EdCottrell 是的,我会在某些条件下放弃其中的许多,然后其他一些会因运营商而放弃。 @ZdaR:一次加载100GB大小的内容是不可能的。不,不需要一次完整的列表。 所以你也必须清理文本?我想你也在把它写到磁盘上? 【参考方案1】:

首先,确保您的文件中有行,然后您可以放心地逐行阅读 (discussed here):

with open('my100GBfile.txt') as corpus:
    for line in corpus:
        sequence = preprocess(line)
        extract_n_grams(sequence)

假设您的语料库不需要任何特殊处理。我想您可以为您的文本找到合适的处理方法,我只希望将其放入理想的标记中:

def preprocess(string):
    # do what ever preprocessing that it needs to be done
    # e.g. convert to lowercase: string = string.lower()
    # return the sequence of tokens
    return string.split()

我不知道你想用 n-gram 做什么。让我们假设您想将它们算作适合您记忆的语言模型(通常是这样,但我不确定 4 克和 5 克)。简单的方法是使用现成的nltk 库:

from nltk.util import ngrams

lm = n:dict() for n in range(1,6)
def extract_n_grams(sequence):
    for n in range(1,6):
        ngram = ngrams(sentence, n)
        # now you have an n-gram you can do what ever you want
        # yield ngram
        # you can count them for your language model?
        for item in ngram:
            lm[n][item] = lm[n].get(item, 0) + 1

【讨论】:

【参考方案2】:

如果您一次不需要整个列表,那么最好的选择应该是使用迭代器。 因此,我的解决方案如下所示:

import re
text = "Spark is a framework for writing fast, distributed programs. Spark solves similar problems as Hadoop MapReduce does but with a fast in-memory approach and a clean functional style API."
word_re = re.compile(r"\w+")
words = [text[word.start():word.end()] for word in word_re.finditer(text)]
ngrams = ((words[k] for k in xrange(j, j + i + 1)) for i in xrange(len(words)) for j in xrange(len(words) - i))
for ngram in ngrams:
    for word in ngram:
        print word,
    print

这会以所需的顺序为您提供所有需要的 ngram。 请注意,即使对于 ngram 本身,迭代器也是不可避免的,因为您的文本高达 500G,并且“所有可能的部分”中的大部分内容都不适合您的记忆。

另请注意,在您的情况下,您需要计算文本的长度并分别从中获取单词,因为您将无法像我的代码示例那样将其保存在内存中。

【讨论】:

【参考方案3】:

理想情况下应该这样做。 您可以自定义参数 min_len 和 max_len 以满足您的需要。 应用排序函数也可以让您很好地了解哪些 n-gram 与众不同。

import nltk
from nltk.util import *
from nltk.collocations import *

content = "Spark is a framework for writing fast, distributed programs. Spark solves similar problems as Hadoop MapReduce does but with a fast in-memory approach and a clean functional style API. ..."
tokens = nltk.word_tokenize(content)
bgs = everygrams(tokens, min_len=users_minimium, max_len=users_maximum)
fdist_bg = nltk.FreqDist(bgs)
for k,v in fdist_bg.items():
        print k,v

由于您提到并行执行,您可以使用 Spark MLib 和 Python 查看以下代码 sn-p

from pyspark.ml.feature import NGram
wordDataFrame = sqlContext.createDataFrame([
(0, ["Hi", "I", "heard", "about", "Spark"]),
(1, ["I", "wish", "Java", "could", "use", "case", "classes"]),
(2, ["Logistic", "regression", "models", "are", "neat"])], ["label","words"])
ngram = NGram(inputCol="words", outputCol="ngrams")
ngramDataFrame = ngram.transform(wordDataFrame)
for ngrams_label in ngramDataFrame.select("ngrams", "label").take(3):
    print(ngrams_label)

Spark 中解决方案和其他特征提取技术的链接在这里:Spark MLib Feature extraction

希望对您有所帮助。干杯。 :)

【讨论】:

【参考方案4】:

我编写了一个 C 库来执行此操作:https://github.com/adriaan-pelzer/corpusToNgrams

基本上,我能想到的最高效的方法是:

逐个字符地解析语料库。 如果遇到单词结尾字符(空格、逗号、句号等),请将单词添加到 1-gram 数组中。 重复 n = 2 到 maxN: 如果 1-gram 数组的长度大于 n,则连接 1-gram 数组的最后 n 个单词并将其添加到 n-gram 数组中。

以上可以用递归函数实现,只需要解析一次语料。

【讨论】:

【参考方案5】:

你写过代码吗?尝试谷歌搜索N-gram generation 或查看这里:Computing N Grams using Python

看起来您想生成 1-gram(单词列表),最多 5-gram。

我会一次性完成每个,然后继续学习 n+1-gram。

【讨论】:

这应该是评论而不是答案,链接问题中的答案也不适用于这种大小的数据,在某些阶段切片将是 100gig

以上是关于从巨大的文本中提取 n 克的主要内容,如果未能解决你的问题,请参考以下文章

在java中从PDF中提取文本的最佳方法

使用 Perl 从巨大的存档中提取单个

从 xz 文件中提取文件

PHP:如何从字符串转储中提取 JSON 字符串

python脚本从巨大的(60000)JSON文件目录中提取特征到csv

如何从 Python 中的文本中提取 2d 年?