文本中重复短语的Python处理
我遇到了一个问题,完全不知道该怎么解决。请给我一些建议。
我有一段文字。非常非常长的文字。我的任务是找出文本中所有重复的短语,这些短语的长度是3,也就是由三个单词组成。
4 个回答
我建议你看看NLTK工具包。这个工具是开源的,主要用于自然语言处理的学习。除了更高级的自然语言处理功能,它还提供了很多关于分词的功能和工具。
最简单的方法就是把文本读成一个字符串。然后用字符串的split()方法把它分成一个个单词,放到一个列表里。接着,你可以每三个单词切分一次这个列表,并使用collections.defaultdict(int)来记录每个短语出现的次数。
d = collections.defaultdict(int)
d[phrase]+=1
就像我说的,这种方法很粗糙。但肯定能让你入门。
看起来你有两个问题。
第一个问题是如何有效地规范化输入。你提到想要找到输入中的所有三字短语,但什么算是一个短语呢?比如说,the black dog
和 The black, dog?
是不是同一个短语?
一种方法是使用像 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')]
这个函数可能还有更简单的版本,但这个效率不错,而且不难理解。
重要的是,把生成器串联在一起只需遍历列表一次,而且不会在内存中创建大的临时数据结构。你可以用结果来构建一个以短语为键的 defaultdict
:
>>> import collections
>>> counts = collections.defaultdict(int)
>>> for phrase in phrases(words(text)):
counts[phrase] += 1
这样在计算短语时只需对 text
进行一次遍历。当完成后,找到字典中所有值大于一的条目。