Python文本中的重复短语

Python文本中的重复短语,python,text,repeat,Python,Text,Repeat,我有一个问题,我不知道如何解决它。请给我一个建议 我有一条短信。大,大文本。任务是找到文本中所有长度为3(包含三个单词)的重复短语。我建议查看NLTK工具包。这是一个开源软件,用于自然语言教学。除了更高级的NLP函数外,它还有许多标记化类型的函数和集合。最粗糙的方法是读取字符串中的文本。执行string.split()并获取列表中的单个单词。然后,您可以每三个单词对列表进行切片,并使用collections.defaultdict(int)来保持计数 d=集合.defaultdict(int)

我有一个问题,我不知道如何解决它。请给我一个建议


我有一条短信。大,大文本。任务是找到文本中所有长度为3(包含三个单词)的重复短语。

我建议查看NLTK工具包。这是一个开源软件,用于自然语言教学。除了更高级的NLP函数外,它还有许多标记化类型的函数和集合。

最粗糙的方法是读取字符串中的文本。执行string.split()并获取列表中的单个单词。然后,您可以每三个单词对列表进行切片,并使用collections.defaultdict(int)来保持计数

d=集合.defaultdict(int)

d[短语]+=1

正如我所说,它非常粗糙。但是你肯定应该开始

这里有一个大致为O(n)的解决方案,它应该适用于相当大的输入文本。如果它太慢,您可能想研究使用Perl,它是为文本处理或C++设计的纯性能。
>>> s = 'The quick brown fox jumps over the lazy dog'
>>> words = string.lower(s).split()
>>> phrases = collections.defaultdict(int)
>>> for a, b, c in zip(words[:-3], words[1:-2], words[2:]):
...     phrases[(a, b, c)] += 1
... 
>>> phrases
defaultdict(<type 'int'>, {('over', 'the', 'lazy'): 1, ('quick', 'brown', 'fox'): 1, ('the', '
quick', 'brown'): 1, ('jumps', 'over', 'the'): 1, ('brown', 'fox', 'jumps'): 1, ('fox', 'jumps
', 'over'): 1})
>>> [phrase for phrase, count in phrases.iteritems() if count > 1]
>>> []
>s='敏捷的棕色狐狸跳过懒惰的狗'
>>>words=string.lower.split()
>>>短语=集合.defaultdict(int)
>>>对于邮政编码的a、b、c(单词[:-3],单词[1:-2],单词[2:]):
...     短语[(a,b,c)]+=1
... 
>>>词组
defaultdict(,{('over','the','lazy'):1,('quick','brown','fox'):1,('the','
“快速”,“棕色”):1,(“跳跃”,“越过”,“the”):1,(“棕色”,“狐狸”,“跳跃”):1,(“狐狸”,“跳跃”)
“,”在“):1})
>>>[短语对短语,在短语中计数。如果计数>1,则为iteritems()]
>>> []

在我看来,你有两个问题

第一个是提出一种规范化输入的有效方法。你说你想在输入中找到所有的三个单词短语,但是短语是由什么组成的呢?例如,
黑狗
黑狗
是同一个短语吗

正如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')]
几乎可以肯定,这个函数有一个更简单的版本,但是这个版本很有效,而且不难理解

值得注意的是,将生成器链接在一起只遍历列表一次,并且不会在内存中构建任何大型临时数据结构。您可以使用结果构建一个
defaultdict
,按短语键入:

>>> import collections
>>> counts = collections.defaultdict(int)
>>> for phrase in phrases(words(text)):
        counts[phrase] += 1

这将在计算短语时,对
文本进行单次传递。完成后,在字典中查找每个值大于1的条目。

具体来说,很难找到大到明显的算法不起作用的文本(列出所有三个单词短语并计算它们)。我在发布此问题之前就开始这样做,但这很粗糙。问题是文本包含大量的sumbol,比如!?:“(?)等。我应该写string.split(对于每个sumbol)?@user
re.findall(r”[\w']+“,“你好,世界!”)
将是一个更好的起点。@user Yes标点符号很快就会变得复杂。如果在句号处拆分,缩写将拆分为多个字母。引号(可能是撇号)呢因此,我认为你必须做出一些假设。要正确地进行这项工作,需要一个分类系统(NLTK也是如此)但这将相对缓慢,并且可能不会带来足够的显著改进。请参阅以下链接以删除标点符号和符号。但是,正如前面的评论所述,它有其自身的缺点。然后,您可能应该按照@winweed的建议查看NLTK。+1。在处理真正的bi时,使用迭代器是唯一的选择g数据。我这边唯一的建议是使用
collections.Counter
(这是
最常用的
方法)而不是
collections.defaultdict
。但这仅在Python>2.7中可用