从巨大的文本中提取 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 克的主要内容,如果未能解决你的问题,请参考以下文章