在python中存储n-gram(带有可变字数的字符串)的最快方法

时间:2013-06-27 14:31:43

标签: python n-gram

我有一个输入文件,由带有数字和单词序列的行组成,结构如下:

\1-grams:
number   w1    number
number   w2    number
\2-grams:
number   w1 w2   number
number   w1 w3   number
number   w2 w3   number
\end\

我希望以这样的方式存储单词序列(所谓的n-gram),以便我可以轻松地为每个唯一的n-gram检索两个数字。我现在做的是以下内容:

all = {}
ngrams = {}
for line in open(file):
    m = re.search('\\\([1-9])-grams:',line.strip()) # find nr of words in sequence
    if m != None:
        n = int(m.group(1))
        ngrams = {} # reinitialize dict for new n
    else:
        m = re.search('(-[0-9]+?[\.]?[0-9]+)\t([^\t]+)\t?(-[0-9]+\.[0-9]+)?',line.strip()) #find numbers and word sequence
        if m != None:
            ngrams[m.group(2)] = '{0}|{1}'.format(m.group(1), m.group(3))
        elif "\end\\" == line.strip():
            all[int(n)] = ngrams

通过这种方式,我可以轻松快速地找到例如数字。顺序s ='w1 w2'这样:

all[2][s]

问题是这个存储过程相当慢,特别是当有很多(> 100k)的n-gram时,我想知道是否有更快的方法来实现相同的结果而不减少访问速度。我在这里做的事情不是很理想吗?我在哪里可以改进?

提前致谢,

里斯

3 个答案:

答案 0 :(得分:6)

我会尝试减少正则表达式搜索。

值得考虑其他一些事情:

  • 将所有数据存储在一个字典中可能会加快速度;带有额外图层的数据层次结构并没有帮助,也许是违反直觉的。

  • 存储元组可以避免调用.format()

  • 在CPython中,函数中的代码比全局代码更快。

以下是它的样子:

def load(filename):
    ngrams = {}
    for line in open(filename):
        if line[0] == '\\':
            pass  # just ignore all these lines
        else:
            first, rest = line.split(None, 1)
            middle, last = rest.rsplit(None, 1)
            ngrams[middle] = first, last
    return ngrams

ngrams = load("ngrams.txt")

我希望存储int(first), int(last)而不是first, last。这将加快访问速度,但减慢加载时间。所以这取决于你的工作量。

我不同意johnthexii:只要数据集适合内存,在Python中执行此操作应该比与数据库(甚至是sqlite)交谈快得多。 (如果您使用数据库,这意味着您可以执行一次加载而不必重复它,因此sqlite最终可能正是您想要的 - 但您无法使用:memory:database。)

答案 1 :(得分:3)

关于代码的优化。

1)在循环之前编译正则表达式。请参阅re.compile的帮助。

2)尽可能避免使用正则表达式。例如" -grams"可以通过简单的字符串比较来检查前缀为数字的字符串

答案 2 :(得分:0)

我个人会使用indexes移动到数据库(sqllite3内置于python)。索引使查询变得快速。 Python还支持in memory sqllite databases

  

您还可以提供特殊名称:memory:在中创建数据库   RAM。