Biorąc pod uwagę big.txt
z norvig.com/big.txt, celem jest naprawdę szybkie policzenie bigramsów (Wyobraź sobie, że muszę to powtarzać 100 000 razy).Liczenie bigramsów naprawdę szybko (z lub bez wieloprocesowości) - python
Według Fast/Optimize N-gram implementations in python, wydobywania bigrams tak byłby najbardziej optymalny:
_bigrams = zip(*[text[i:] for i in range(2)])
A jeśli używam Python3
, generator nie będą oceniane, dopóki nie zmaterializować ją list(_bigrams)
lub niektórych innych funkcji to zrobi to samo.
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)
Ale to trwa około 1+ sekund na iterację, a 100 000 powtórzeń będzie zbyt długich.
Próbowałem również Counterizerzy Counter-to-detectora, ale czas na wyodrębnienie, policzenie i uzyskanie top100 bigramów jest porównywalny z rodzimym pytonem.
Potem już eksperymentował z jakiegoś multiprocessing
, wykorzystując niewielką modyfikację od Python multiprocessing and a shared counter i 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))
Ale używając MultiProcCounter
w liczeniu dwuznaków trwa nawet dłużej niż 1+ sekund na iteracji. Nie mam pojęcia, dlaczego tak jest, przy użyciu przykładowej listy int
przykład, multiproc_count
działa idealnie.
Próbowałem:
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)
Czy istnieje jakiś sposób, aby policzyć bigrams bardzo szybko w Pythonie?
Wygląda na to, że powinieneś zajrzeć do przetwarzania rozproszonego i mapować/zmniejszać, jeśli naprawdę nie możesz uniknąć wykonywania tego samego 100 000 razy. Zakładam, że masz na myśli, że masz dane, które są jeszcze większe, nie że dosłownie powtarzają te same obliczenia 100 000 razy; jeśli tak naprawdę masz na myśli, to brzmi jak błąd w twoim podstawowym planie. – tripleee
Powtarza to samo 100 000 razy, ale za każdym razem zajmuje top100 bigrams i manipuluje tekstem, więc tekst wejściowy do wyodrębnienia bigramów jest różny w każdej iteracji. – alvas
Czy uważasz, że pierwsze 20 bigrams of big.txt to ["th", "on", "e", "p", "pr", "ro", "oj", "je", "ec", "ct", "t", "g ',' gu ',' ut ',' te ',' en ',' nb ',' be ',' er ',' rg '], jak generuje twój kod, lub podzbiór zorientowany na słowa, taki jak [' th ' "he", "pr", "ro", "oj", "je", "ec", "ct", "gu", "ut", "te", "en", "nb", " być "," er "," rg "," eb "," bo "," oo "," ok "]? Po prostu staram się zrozumieć zasady gry. – cdlane