2016-03-01 3 views
0

Я пытаюсь ускорить свое приложение, и я обнаружил, что простая небольшая функция ниже (compute_ave_freq) на самом деле является одним из самых больших часовых свиней. Преступник, похоже, когда он рассыпает NLTK FreqDist; это требует непристойного количества времени.Более быстрый способ хранения NLTK FreqDict?

Конечно, даже это непристойное количество времени меньше половины того, что потребуется для вычисления FreqDist заново. Есть ли лучший способ сохранить объект NLTK FreqDist? Я попробовал сериализовать его как JSON, но это сохраняет его как простой словарь, теряя много функциональности NLTK, которые мне нужны.

Вот код:

def compute_ave_freq(word_forms):  
    fd = pickle.load(open("data/fd.txt", 'rb')) 
    total_freq = 0 
    for form in word_forms: 
     freq = fd.freq(form) 
     total_freq += freq 
    try: 
     ave_freq = total_freq/len(word_forms) 
    except ZeroDivisionError: 
     ave_freq = 0 
    return ave_freq 

А вот выход LineProfiler:

Total time: 0.197121 s 
File: /home/username/development/appname/filename.py 
Function: compute_ave_freq at line 25 
Line #  Hits   Time Per Hit % Time Line Contents 
============================================================== 
25           def compute_ave_freq(word_forms, debug=False): 
26            # word_forms is a list of morphological variations of a word, such as 
27            # ['كتبوا', 'كتبو', 'كتبنا', 'كتبت'] 
28           
29   1  78580 78580.0  79.1  fd = pickle.load(open("data/fd.txt", 'rb')) 
30   1   3  3.0  0.0  total_freq = 0 
31   5   10  2.0  0.0  for form in word_forms: 
32   4  20676 5169.0  20.8   freq = fd.freq(form) 
33   4   9  2.2  0.0   if debug==True: 
34              print(form, '\n', freq) 
35   4   6  1.5  0.0   total_freq += freq 
36   1   1  1.0  0.0  try: 
37   1   3  3.0  0.0   ave_freq = total_freq/len(word_forms) 
38            except ZeroDivisionError: 
39             ave_freq = 0 
40   1   1  1.0  0.0  return ave_freq 

Спасибо!

+0

Unpickling загружается в оперативную память, и это довольно трудно проблемой справиться, но как только он загружен, это хорошо. Возможно, включение его в некоторые БД (например, SQL/Mongo) было бы лучшим способом работы с большими наборами данных. В противном случае просто подождите некоторое время, чтобы загрузить его в ОЗУ. – alvas

+0

Я думаю, что общее правило может заключаться в том, что «Если у вас есть набор данных, который можно полностью загрузить в ОЗУ без особого напряжения, то на самом деле это не так уж и важно, и время, затраченное на индексирование/запрос БД, может быть не существенным». – alvas

+2

Переместить 'fd = pickle.load (open (" data/fd.txt ", 'rb'))' вне функции и просто передать ее функции, если 'fd' изменяется, то есть' def compute_ave_freq (word_forms, fd) : '. В противном случае, если 'fd' не изменяется, просто сделайте' fd' глобальную переменную и загрузите ее один раз. – alvas

ответ

1

Как было предложено в комментариях, переместите переменную fd за пределами функции должны решить эту проблему:

fd = pickle.load(open("data/fd.txt", 'rb')) 

def compute_ave_freq(word_forms):  
    total_freq = 0 
    for form in word_forms: 
     freq = fd.freq(form) 
     total_freq += freq 
    try: 
     ave_freq = total_freq/len(word_forms) 
    except ZeroDivisionError: 
     ave_freq = 0 
    return ave_freq 

Но поскольку вы создаете функцию суммы усреднения, здесь более простая реализация:

fd = pickle.load(open("data/fd.txt", 'rb')) 

def compute_ave_freq(word_forms): 
    try: 
     return sum([fd.freq(form) for form in word_forms])/len(word_forms) 
    except ZeroDivisionError: 
     return 0 

Или:

fd = pickle.load(open("data/fd.txt", 'rb')) 

def compute_ave_freq(word_forms): 
    l = len(word_forms) 
    if l > 0: 
     return sum([fd.freq(form) for form in word_forms])/l 
    else: 
     return 0 

Или проще:

fd = pickle.load(open("data/fd.txt", 'rb')) 

def compute_ave_freq(word_forms): 
    l = len(word_forms) 
    return sum([fd.freq(form) for form in word_forms])/l if l > 0 else 0 

Или с lambda:

fd = pickle.load(open("data/fd.txt", 'rb')) 
compute_ave_freq = lambda x: sum(fd.freq(i) for i in x)/len(x) 
ave_freq = compute_ave_freq(word_forms) if len(word_forms) > 0 else 0 

ли смотреть на EAFP and LBYL

+0

Еще раз спасибо, и спасибо за ссылку. Я использовал первый вариант, который вы предложили (со списком), потому что 'lambda' заставляет мою голову болеть ... :-) – larapsodia

Смежные вопросы