Быстрый способ удаления стоп-слов в 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') С

спасибо.

3 ответов


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

    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. Соответствующие строки размещены ниже.

nCalls совокупного времени

10000 7.723 слов.py: 7 (testFuncOld)

10000 0.140 слов.py: 11 (testFuncNew)

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


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

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

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

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


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

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() на самом деле быстрый.

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