我正在研究一个医学术语数据库(网格和uniprot),我正在解析许多医学论文(发表),搜索论文中的术语匹配。这两个数字都是惊人的(约300k项和约6.5M论文),因此匹配算法必须尽可能高效。
目前我正在做这样的事情:
foo = "some long and boring medical paper [...] that I'm searching"
bar = [["array of medical terms matched with an unique code",1],
["also they are sorted by length",2]]
for term in bar:
if term[0] in foo:
repetitions = foo.count(term[0])
array_to_be_inserted_in_database.append(term[1],repetitions)
注意:foo
来自NLTK语料库生成器(省略以保持示例简单),array_to_be_inserted_in_database
正如其名称所示;当我完成bar
检查时,我将所有内容保存在MongoDB中并转到下一篇论文。
问题:
我不习惯正则表达式,它们在速度方面是否值得?化学化合物和医学术语也充满了转义字符(例如:(1-5)-methylbuthyl*-ethyl-something
),你如何“中和”它们以免它们干扰RE?
in
比RE更快
t= timeit.Timer(
're.subn(regex,"",frase)',
setup = 'import re; frase = "el gato gordo de la abuela"; palabra = "gordo"; regex = re.compile(palabra)'
)
ordenes = """\
if palabra in frase:
numero = frase.count(palabra)
frase.replace(palabra,"")
"""
y= timeit.Timer(stmt= ordenes,setup = 'frase = "el gato gordo de la abuela"; palabra = "gordo"'
)
print t.timeit(number = 1000)
print y.timeit(number = 1000)
答案 0 :(得分:1)
如果您只处理逐字字符串(而不是模式),并且您不介意gut
之类的字词也会匹配gutter
这样的较长字词,然后in
可能会更快。
另一方面,您可以使用re.findall()
一次完成所有匹配并获得结果列表的长度,这样您就不必经历两次字符串(一次查找) ,一次计数)。中和特殊字符很容易 - 只需在字符串上调用re.escape()
,它就会确保文本按原样匹配。
最后,唯一可以肯定的方法是针对实际数据测试这两种解决方案。
答案 1 :(得分:0)
不是单独搜索所有术语,而是可以在所有论文上创建索引,列出哪些单词出现在哪些论文中,然后只搜索包含所有相关单词的论文。这样,您必须扫描每张纸一次以构建索引,然后您只需要对那些您知道它们包含所有相关术语的论文进行全文搜索。
非常简单的伪代码:
# get interesting words
interesting_words = set(word for term in terms for word in term.split())
# build index, mapping interesting words to papers they appear in
index = defaultdict(set)
for paper in papers:
for word in paper.text:
if word in interesting_words:
index[word].add(paper)
# find full terms in papers that have all the words, according to the index
for term in terms:
interesting = reduce(set.intersection, (index[word] for word in term.split()))
for paper in interesting:
if term in interesting.text:
full term found
(注意:我不是索引/数据检索的专家,可能有更好的方法来创建这样的索引,也可能还有一些已经这样做的库。)