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

nie*_*nen 0 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\
Run Code Online (Sandbox Code Playgroud)

我希望以这样的方式存储单词序列(所谓的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
Run Code Online (Sandbox Code Playgroud)

通过这种方式,我可以通过这种方式轻松快速地找到序列s ='w1 w2'的数字:

all[2][s]
Run Code Online (Sandbox Code Playgroud)

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

提前致谢,

里斯

Jas*_*rff 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")
Run Code Online (Sandbox Code Playgroud)

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

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

  • 一个非常好的答案,但我将if/else块更改为`if not line [0] =='\\':`,这样可以节省两行代码:) (2认同)