У меня, как мне кажется, две проблемы.
Первый - эффективный способ нормализации ввода.Вы говорите, что хотите найти все фразы из трех слов во входных данных, но из чего состоит фраза?Например, the black dog
и The black, dog?
- это одна и та же фраза?
Способ сделать это, как предполагает marcog, - использовать что-то вроде re.findall
.Но это довольно неэффективно: он обходит весь ваш ввод и копирует слова в список, а затем вам нужно обработать этот список.Если ваш вводимый текст очень длинный, это будет расточительно как по времени, так и по пространству.
Лучшим подходом было бы рассматривать входные данные как поток и создать генератор, который выполняет по одному слову за раз.,Вот пример, который использует пробелы в качестве разделителя между словами, затем удаляет из слов не-буквенные символы и преобразует их в нижний регистр:
>>> def words(text):
pattern = re.compile(r"[^\s]+")
non_alpha = re.compile(r"[^a-z]", re.IGNORECASE)
for match in pattern.finditer(text):
nxt = non_alpha.sub("", match.group()).lower()
if nxt: # skip blank, non-alpha words
yield nxt
>>> text
"O'er the bright blue sea, for Sir Joseph Porter K.C.B."
>>> list(words(text))
['oer', 'the', 'bright', 'blue', 'sea', 'for', 'sir', 'joseph', 'porter', 'kcb']
Вторая проблема - группировка нормализованных слов в трисловосочетания.Опять же, вот место, где генератор будет работать эффективно:
>>> def phrases(words):
phrase = []
for word in words:
phrase.append(word)
if len(phrase) > 3:
phrase.remove(phrase[0])
if len(phrase) == 3:
yield tuple(phrase)
>>> list(phrases(words(text)))
[('oer', 'the', 'bright'), ('the', 'bright', 'blue'), ('bright', 'blue', 'sea'), ('blue', 'sea', 'for'), ('sea', 'for', 'sir'), ('for', 'sir', 'joseph'), ('sir', 'joseph', 'porter'), ('joseph', 'porter', 'kcb')]
Почти наверняка возможна более простая версия этой функции, но она эффективна, и ее нетрудно понять.
* 1017Примечательно, что объединение генераторов в цепочку происходит только один раз, и оно не создает больших временных структур данных в памяти.Вы можете использовать результат для построения
defaultdict
, набираемого по фразе:
>>> import collections
>>> counts = collections.defaultdict(int)
>>> for phrase in phrases(words(text)):
counts[phrase] += 1
Это делает один проход по text
при подсчете фраз.Когда это будет сделано, найдите в словаре каждую запись, значение которой больше единицы.