Почему так много различий в скорости этих двух вариантов? - PullRequest
4 голосов
/ 24 апреля 2019

Версия 1

import string, pandas as pd
def correct_contraction1(x, dic):
    for word in dic.keys():
        if word in x:
            x = x.replace(word, " " + dic[word]+ " ")
    return x

Версия 2

import string, pandas as pd
def correct_contraction2(x, dic):
    for word in dic.keys():
        if " " + word + " " in x:
            x = x.replace(" " + word + " ", " " + dic[word]+ " ")
    return x

Как я их использую:

train['comment_text'] = train['comment_text'].apply(correct_contraction1,args=(contraction_mapping,))
#3 mins 40 sec without that space thing (version1)

train['comment_text'] = train['comment_text'].apply(correct_contraction2,args=(contraction_mapping,))
#5 mins 56 sec with that space thing (version2)

Может кто-нибудь объяснить, почему существует такая большая разница в скорости, которая, скорее всего, не должна иметь место, и, во-вторых, какой-нибудь лучший / скрытый трюк панд для дальнейшей оптимизации?(Код несколько раз тестировался на ядрах Kaggle)

  • train - это фрейм данных с 2 миллионами строк в обоих случаях, также абсолютно идентичный
  • contraction_mappingэто словарное отображение ... (одинаково в обоих случаях)
  • Последние панды, надеюсь.

Большое спасибо!

Редактировать -1 - Данные приходятиз Kaggle Comp , Версия 1 намного быстрее!

Редактировать -2 Спасибо, вы, ребята, Рок! (Я хотел бы принять их всех!)

Ответы [ 3 ]

5 голосов
/ 24 апреля 2019

Извините, что не отвечаю на разницу, но текущий подход может быть легко улучшен в любом случае.Это идет медленно для вас, потому что вам придется сканировать все предложения несколько раз (для каждого слова).Вы даже проверяете каждое слово дважды, сначала, если оно есть, а затем заменить его - вы можете просто заменить только.

Это важный урок при замене текста, будь то регулярное выражение, простая замена строкиили даже когда вы разрабатываете свой собственный алгоритм: попробуйте просмотреть текст только один раз.Независимо от того, сколько слов вы хотите заменить.Регулярное выражение проходит долгий путь, но в зависимости от реализации необходимо возвращаться назад на несколько символов, когда оно не находит попадания.Для интересующихся: ищите структуру данных trie.

Попробуйте, например, реализацию быстрого текстового поиска (aho-corasick).Я разрабатываю для этого библиотеку, но до тех пор вы можете использовать flashtext (что немного по-другому):

import flashtext
# already considers word boundaries, so no need for " " + word " "
fl = flashtext.KeywordProcessor()
fl.add_keywords_from_dict(dic)

train['comment_text'] = train['comment_text'].apply(fl.replace_keywords)

Если вам нужно заменить много слов, это будетна порядок быстрее.

Для сравнения по первым данным я смог найти:

Words to replace: 8520
Sentences to replace in: 11230
Replacements made using flashtext: 1706
Replacements made using correct_contraction1: 25 

flashtext: (considers word boundaries and ignores case)
39 ms ± 355 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

correct_contraction1: (does not consider case nor words at end of line)
11.9 s ± 194 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

<unannounced>
30 ms ± 366 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

Итак, мы говорим об ускорении в 300 раз.Это случается не каждый день; -)

Для справки добавил способ регулярных выражений Джона Клемента:

pandas.str.replace + regex (1733 replacements)
3.02 s ± 82.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Моя новая библиотека уменьшит еще 30%, как я ее проверил.Я видел улучшение в 2-3 раза по сравнению с flashtext, но, что более важно, предоставил вам, как пользователю, больше контроля.Он полностью функционален, просто нужно его почистить и добавить больше документации.

Я обновлю ответ, когда он прибудет!

1 голос
/ 24 апреля 2019

Вторая версия должна выполнять конкатенацию " " + word + " " каждый раз в цикле, и когда она находит совпадение, она делает это во второй раз для выполнения замены. Это делает его медленнее.

Нельзя избежать первой конкатенации (если вы не измените dic, чтобы ключи уже имели пробелы вокруг них). Но вы можете избежать второй конкатенации, сохранив ее в переменной в первый раз. Это все равно будет медленнее, чем в первой версии, но не намного.

def correct_contraction2(x, dic):
    for word in dic.keys():
        spaceword = " " + word + " "
        if spaceword in x:
            x = x.replace(spaceword, " " + dic[word]+ " ")
    return x

Также кажется, что вторая версия может работать некорректно во всех случаях. Если слово находится в начале или конце строки, оно не будет окружено пробелами. Возможно, лучше использовать регулярное выражение с \b для сопоставления границ слова.

1 голос
/ 24 апреля 2019

Вам лучше использовать здесь Series.str.replace Pandas и предоставить ему скомпилированное регулярное выражение, основанное на содержимом таблицы поиска.Это означает, что операции по замене строк могут работать в Series быстрее, чем применение функции, это также означает, что вы не сканируете строку так, как обычно, гораздо чаще, чем нужно ... Надеемся, что это сократит ваше время до секунд.минут.

import re
import pandas as pd

corrections = {
    "it's": "it is",
    "can't": "can not",
    "won't": "will not",
    "haven't": "have not"
}

sample = pd.Series([
    "Stays the same",
    "it's horrible!",
    "I hope I haven't got this wrong as that won't do",
    "Cabbage"
])

Затем создайте свое регулярное выражение так, чтобы оно отыскивало любые возможные совпадения, которые являются ключами в вашем словаре, без учета регистра и с учетом границ слов:

rx = re.compile(r'(?i)\b({})\b'.format('|'.join(re.escape(c) for c in corrections)))

Затем примените к вашему столбцу(например, измените sample на training['comment_text']) str.replace, передающий регулярное выражение и функцию, которая принимает совпадение и возвращает совпадающее значение для найденного ключа:

corrected = sample.str.replace(rx, lambda m: corrections.get(m.group().lower()))

Тогда у вас будетcorrected как серия, содержащая:

['Stays the same',
 'it is horrible!',
 'I hope I have not got this wrong as that will not do',
 'Cabbage']

Обратите внимание на регистр It's ... он был выбран без учета регистра и вместо него превращен в it is ... Существуют различные способы сохранить регистр, ноэто, вероятно, не очень важно, и совсем другой вопрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...