Быстрый способ удаления стоп-слов в 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 вместо возврата массива. я считаю посмотреть thist hread почему regex
было бы хорошей заменой здесь.s.split()
на самом деле быстрый.
наконец, выполните такую работу параллельно (удаление стоп-слов в строках 6m). Это совсем другая тема.