给定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))
但是在bigram计数中使用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中bigrams的方法?
o → a
替换为dog
中的o
时,可以将do
和og
减少并将da
和ag
增加。如果大部分文本没有更改,则应该比重复计算更快。 - Palec