Подтвердить что ты не робот

Более быстрый способ удаления стоп-слов в Python

Я пытаюсь удалить стоп-слова из строки текста:

from nltk.corpus import stopwords
text = 'hello bye the the hi'
text = ' '.join([word for word in text.split() if word not in (stopwords.words('english'))])

Я обрабатываю 6 мил таких строк, поэтому скорость важна. Профилирование моего кода, самая медленная часть - это строки выше, есть ли лучший способ сделать это? Я думаю использовать что-то вроде regex re.sub, но я не знаю, как написать шаблон для набора слов. Может кто-то дать мне руку, и я также рад услышать другие, возможно, более быстрые методы.

Примечание. Я попробовал, чтобы кто-то предложил обернуть stopwords.words('english') с помощью set(), но это не имело значения.

Спасибо.

4b9b3361

Ответ 1

Попробуйте кэшировать объект стоп-слов, как показано ниже. Построение этого каждый раз, когда вы вызываете функцию, кажется узким местом.

    from nltk.corpus import stopwords

    cachedStopWords = stopwords.words("english")

    def testFuncOld():
        text = 'hello bye the the hi'
        text = ' '.join([word for word in text.split() if word not in stopwords.words("english")])

    def testFuncNew():
        text = 'hello bye the the hi'
        text = ' '.join([word for word in text.split() if word not in cachedStopWords])

    if __name__ == "__main__":
        for i in xrange(10000):
            testFuncOld()
            testFuncNew()

Я провел это через профайлер: python -m cProfile -s кумулятивный test.py. Соответствующие строки размещены ниже.

nCallulative Time

10000 7.723 words.py:7(testFuncOld)

10000 0.140 words.py:11(testFuncNew)

Итак, кеширование экземпляра стоп-слов дает ускорение ~ 70x.

Ответ 2

Используйте regexp для удаления всех слов, которые не соответствуют:

import re
pattern = re.compile(r'\b(' + r'|'.join(stopwords.words('english')) + r')\b\s*')
text = pattern.sub('', text)

Это, вероятно, будет быстрее, чем цикл, особенно для больших входных строк.

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

Ответ 3

Сначала вы создаете стоп-слова для каждой строки. Создайте его один раз. Множество было бы здорово здесь.

forbidden_words = set(stopwords.words('english'))

Позже избавьтесь от [] внутри join. Вместо этого используйте генератор.

' '.join([x for x in ['a', 'b', 'c']])

заменить на

' '.join(x for x in ['a', 'b', 'c'])

Следующая вещь, с которой нужно иметь дело, заключалась в том, чтобы сделать значения .split() yield вместо возвращения массива. Я считаю, что regex будет хорошей заменой здесь. См. thist hread, почему s.split() на самом деле быстро.

Наконец, выполните такое задание параллельно (удаление стоп-слов в строках длиной 6 м). Это совершенно другая тема.

Ответ 4

Извините за поздний ответ. Будет полезным для новых пользователей.

  • Создать словарь стоп-слов с использованием библиотеки коллекций
  • Используйте этот словарь для очень быстрого поиска (время = O (1)), а не в списке (время = O (стоп-слова))

    from collections import Counter
    stop_words = stopwords.words('english')
    stopwords_dict = Collections.counter(stop_words)
    text = ' '.join([word for word in text.split() if word not in stopword_dict])