我有一个输入文件,由带有数字和单词序列的行组成,结构如下:
\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时,我想知道是否有更快的方法来实现相同的结果而不减少访问速度。我在这里做的事情不是很理想吗?我在哪里可以改进?
提前致谢,
里斯
答案 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。