【问题标题】:Fastest way to store n-grams (strings with variable amount of words) in python在 python 中存储 n-gram(字数可变的字符串)的最快方法
【发布时间】:2013-06-25 02:54:30
【问题描述】:

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

\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时,我想知道是否有更快的方法来实现相同的结果而不会减少访问速度。我在这里做的不是最理想的吗?哪里可以改进?

提前致谢,

乔里斯

【问题讨论】:

  • all 是一个内置函数。不要重复使用此名称。
  • 哪个慢:从磁盘加载数据,还是使用它?两者都有?
  • 使用数据很慢。我不知道有办法优化“for l in open(f)”?!
  • @Elazar:是的,不好的做法,我同意。
  • @niefpaarschoenen:我的意思是问:这很慢,您发布的解析数据并将其放入字典的代码;还是之后使用字典的代码?

标签: python n-gram


【解决方案1】:

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

还有一些值得考虑的事情:

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

  • 存储元组可以避免调用.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: 数据库来做到这一点。)

【讨论】:

  • 一个很好的答案,但我会将 if/else 块更改为简单的if not line[0] == '\\':,这样可以节省两行代码:)
  • @l4mpi 你可能是对的!我这样写是因为pass 上的评论解释了这与原始代码之间的巨大差异。似乎值得把它放在前面。
  • 确实不错的答案,现在测试您的建议。会尽快给予反馈。
  • 我已经可以说,就我的目的而言,存储字符串比存储数字更可取(实际上是浮点数,而不是整数,但我没有指定),因为解析很慢并且访问速度很慢好的。
  • 我设法将处理时间减少了大约 50%,主要是通过摆脱正则表达式。使用单个字典实际上会减慢它的速度!使用元组也无济于事;如果有的话,它平均比字符串格式慢一点。令人沮丧的是,读取这些相同文件的 C 实现仍然快 10 倍。
【解决方案2】:

关于代码的优化。

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

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

【讨论】:

  • 这有很大的不同!
【解决方案3】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-04
    • 2017-12-09
    • 1970-01-01
    • 2011-05-11
    • 2013-10-13
    相关资源
    最近更新 更多