【发布时间】:2017-03-15 09:06:59
【问题描述】:
鉴于norvig.com/big.txt 中的big.txt,目标是非常快速地计算二元组(想象一下,我必须重复这个计数 100,000 次)。
根据Fast/Optimize N-gram implementations in python,像这样提取二元组是最理想的:
_bigrams = zip(*[text[i:] for i in range(2)])
如果我使用Python3,生成器将不会被评估,直到我使用list(_bigrams) 或其他一些会执行相同操作的函数实现它。
import io
from collections import Counter
import time
with io.open('big.txt', 'r', encoding='utf8') as fin:
text = fin.read().lower().replace(u' ', u"\uE000")
while True:
_bigrams = zip(*[text[i:] for i in range(2)])
start = time.time()
top100 = Counter(_bigrams).most_common(100)
# Do some manipulation to text and repeat the counting.
text = manipulate(text, top100)
但是每次迭代大约需要 1 秒以上的时间,而 100,000 次迭代太长了。
我也尝试过sklearn CountVectorizer,但提取、计数和获取前 100 个二元组的时间与原生 python 相当。
然后我尝试了一些multiprocessing,使用了Python multiprocessing and a shared counter和http://eli.thegreenplace.net/2012/01/04/shared-counter-with-pythons-multiprocessing的轻微修改:
from multiprocessing import Process, Manager, Lock
import time
class MultiProcCounter(object):
def __init__(self):
self.dictionary = Manager().dict()
self.lock = Lock()
def increment(self, item):
with self.lock:
self.dictionary[item] = self.dictionary.get(item, 0) + 1
def func(counter, item):
counter.increment(item)
def multiproc_count(inputs):
counter = MultiProcCounter()
procs = [Process(target=func, args=(counter,_in)) for _in in inputs]
for p in procs: p.start()
for p in procs: p.join()
return counter.dictionary
inputs = [1,1,1,1,2,2,3,4,4,5,2,2,3,1,2]
print (multiproc_count(inputs))
但在二元计数中使用MultiProcCounter 每次迭代需要的时间甚至超过 1 秒。我不知道为什么会这样,使用int 的虚拟列表示例,multiproc_count 可以完美运行。
我试过了:
import io
from collections import Counter
import time
with io.open('big.txt', 'r', encoding='utf8') as fin:
text = fin.read().lower().replace(u' ', u"\uE000")
while True:
_bigrams = zip(*[text[i:] for i in range(2)])
start = time.time()
top100 = Counter(multiproc_count(_bigrams)).most_common(100)
有没有办法在 Python 中真正快速地计算二元组?
【问题讨论】:
-
如果您确实无法避免执行相同的操作 100,000 次,那么您应该研究分布式处理和 map/reduce。我假设您的意思是您拥有更大的数据,而不是您实际上重复相同的计算 100,000 次;如果这真的是你的意思,那听起来你的基本计划有缺陷。
-
它重复相同的事情 100,000 次,但每次都需要前 100 个二元组并操作文本,因此每次迭代时提取二元组的输入文本都不同。
-
你认为big.txt的前20个二元组是['th', 'he', 'e', 'p', 'pr', 'ro', 'oj', 'je'、'ec'、'ct'、't'、'g'、'gu'、'ut'、'te'、'en'、'nb'、'be'、'er'、'rg '] 作为您的代码生成的,或面向单词的子集,例如 ['th', 'he', 'pr', 'ro', 'oj', 'je', 'ec', 'ct', 'gu' , 'ut', 'te', 'en', 'nb', 'be', 'er', 'rg', 'eb', 'bo', 'oo', 'ok']?只是想了解游戏规则。
-
编辑是否如此复杂以至于您无法在更改文本时更新二元计数?例如。当您将
o → a替换为dog时,您可以减少do和og并增加da和ag。如果大部分文本没有变化,这应该比重复计算要快。 -
是的,更新二元组的计数是可能的,但这意味着我需要一个 n^2 的哈希表,因为 n 是没有的。字符数,在某些情况下,n=300,000 =(
标签: python optimization mapreduce counter n-gram