Python 连续词频率计数的有效方法?

Python 连续词频率计数的有效方法?,python,string,parsing,text,Python,String,Parsing,Text,我有这样一个字符串: inputString = "this is the first sentence in this book the first sentence is really the most interesting the first sentence is always first" { 'always first': 0, 'book the': 0, 'first': 0, 'first sentence': 0, 'in th

我有这样一个字符串:

inputString = "this is the first sentence in this book the first sentence is really the most interesting the first sentence is always first"
{   
   'always first': 0,
    'book the': 0,
    'first': 0,
    'first sentence': 0,
    'in this': 0,
    'interesting the': 0,
    'is always': 0,
    'is really': 0,
    'is the': 0,
    'most interesting': 0,
    'really the': 0,
    'sentence in': 0,
    'sentence is': 0,
    'the first': 0,
    'the first sentence': 0,
    'the first sentence is': 0,
    'the most': 0,
    'this': 0,
    'this book': 0,
    'this is': 0
}
还有一本这样的字典:

inputString = "this is the first sentence in this book the first sentence is really the most interesting the first sentence is always first"
{   
   'always first': 0,
    'book the': 0,
    'first': 0,
    'first sentence': 0,
    'in this': 0,
    'interesting the': 0,
    'is always': 0,
    'is really': 0,
    'is the': 0,
    'most interesting': 0,
    'really the': 0,
    'sentence in': 0,
    'sentence is': 0,
    'the first': 0,
    'the first sentence': 0,
    'the first sentence is': 0,
    'the most': 0,
    'this': 0,
    'this book': 0,
    'this is': 0
}

在输入字符串的一次传递中更新此字典的频率计数的最有效方法是什么(如果可能的话)?我有一种感觉,必须有一种解析器技术来做这件事,但我不是这方面的专家,所以我被卡住了。有什么建议吗?

检查一下算法。

当遇到这个问题时,我想,“我知道,我会使用正则表达式”

首先列出所有图案,按长度递减排序:

patterns = sorted(counts.keys(), key=len, reverse=True)
现在将其转换为单个大规模正则表达式,它是每个模式之间的交替:

allPatterns = re.compile("|".join(patterns))
现在在输入字符串上运行该模式,并在运行时计算每个模式的点击数:

pos = 0
while (True):
    match = allPatterns.search(inputString, pos)
    if (match is None): break
    pos = match.start() + 1
    counts[match.group()] = counts[match.group()] + 1
您将得到每个字符串的计数

(旁白:我相信大多数好的正则表达式库都会使用e.dan提到的Aho-Corasick算法在固定字符串上编译一个大的替换。使用正则表达式库可能是应用此算法的最简单方法。)

有一个问题:如果一个模式是另一个模式的前缀(例如“first”和“first-statement”),那么只有较长的模式会得到一个计数。这是出于设计:这就是开始时按长度排序的目的

我们可以将其作为后处理步骤来处理;检查计数,当一个模式是另一个模式的前缀时,将较长模式的计数添加到较短模式的计数中。注意不要重复添加。这只是一个嵌套循环:

correctedCounts = {}
for donor in counts:
    for recipient in counts:
        if (donor.startswith(recipient)):
            correctedCounts[recipient] = correctedCounts.get(recipient, 0) + counts[donor]
该词典现在包含了实际的计数。

这似乎是一条明确的道路,但如果我需要一个简单的Python实现,我会写:

import collections

def consecutive_groups(seq, n):
    return (seq[i:i+n] for i in range(len(seq)-n))

def get_snippet_ocurrences(snippets):
    split_snippets = [s.split() for s in snippets]
    max_snippet_length = max(len(sp) for sp in split_snippets)
    for group in consecutive_groups(inputString.split(), max_snippet_length):
        for lst in split_snippets:
            if group[:len(lst)] == lst:
                yield " ".join(lst)

print collections.Counter(get_snippet_ocurrences(snippets))
# Counter({'the first sentence': 3, 'first sentence': 3, 'the first': 3, 'first': 3, 'the first sentence is': 2, 'this': 2, 'this book': 1, 'in this': 1, 'book the': 1, 'most interesting': 1, 'really the': 1, 'sentence in': 1, 'is really': 1, 'sentence is': 1, 'is the': 1, 'interesting the': 1, 'this is': 1, 'the most': 1})

尝试使用或存储单词而不是字符。

只需浏览字符串并使用字典,就像通常增加任何出现次数一样。这是O(n),因为字典查找通常是O(1)。我经常这样做,即使是收集大量的单词

这是一个非常酷的算法。然而,实施起来令人畏惧@汤姆:似乎有一个Python实现:+1哇。。。看起来正是我想要的。非常感谢!你可以写:
patterns=sorted(counts.keys(),key=len,reverse=True)
@tokland:我不知道。我将把它编辑成答案,谢谢。@TomAnderson:+1非常感谢。非常好用。但是,我似乎遇到了一些问题,因为我收到了以下错误消息:
溢出错误:正则表达式代码大小超出了限制
您是否知道此问题的解决方法?@Legend:是的。使用更少或更短的图案!遗憾的是,我不知道解决这个问题的有效方法。您可以尝试重写正则表达式以使其更小(通过查找公共前缀);我不知道这是否真的有用。