Python 3 - 使用大型列表进行高效查找

时间:2015-05-20 02:38:26

标签: python nltk

我使用NLTK制作自己的押韵是Python。 CMU-dict有超过130,000个条目,格式如下:

[['griffon', ['G', 'R', 'IH1', 'F', 'AH0', 'N']],
 ['griffy', ['G', 'R', 'IH1', 'F', 'IY0']],
 ['grigas', ['G', 'R', 'AY1', 'G', 'AH0', 'Z']]]

这些是单词,pron(unciation)对。我操纵了它们(可能会为一个' T'切换一个' G)并检查它是否是一个单词。我这样做是通过使用这个函数:

all_word_prons = get_word_pron_pairs_in_cmu_dict()

def pron_is_a_word(pronunciation):
    for word, pron in all_word_prons:
        if pronunciation == pron:
            return True
        else:
            return False

all_word_prons是一个Python Pickle文件,它是10mb并包含所有130k条目

如果我执行此查找1000次,则需要大约23秒,考虑到任务并不是完全错误,但必须有更好的算法。我已经看到人们推荐关于其他主题的二等分设置,但那些适用于简单的字符串查找。这或多或少地检查列表是否相等,而不是字符串。

我确实实现了一些包含这样数据的树状结构(使用上面的示例):

{'G': {'R': {'IH1': {'F': {'IY0': {0: 'griffy'}, 'AH0': {'N': {0: 'griffon'}}}}, 'AY1': {'G': {'AH0': {'Z': {0: 'grigas'}}}}}}}

由于某种原因,这需要比简单地迭代它更长的时间。也许我的实施是错误的。如果你有点好奇:

def build_fast_idict_tree():
    from nltk.corpus import cmudict
    entries = cmudict.entries()
    idict = {}
    for entry in entries:
        word, pronunciation = entry
        idict_level = idict
        for syl in pronunciation:
            if syl not in idict_level:
                idict_level[syl] = {}
            idict_level = idict_level[syl]
        idict_level[0] = word
    return idict

def get_fast_idict_tree():
    filename = "fast_idict_tree.pickle"
    if os.path.isfile(filename):
        list = pickle.load(open(filename, "rb"))
    else:
        list = build_fast_idict_tree()
        pickle.dump(list, open(filename, "wb"))
    return list

def lookup_in_fast_idict_tree(syls):
    idict = get_fast_idict_tree()
    for syl in syls:
        if syl not in idict:
            return False
        idict= idict[syl]
    return idict[0] if 0 in idict else False

TL:DR

2015年在Python 3中进行此类查找(匹配列表)的最快方法是什么?

2 个答案:

答案 0 :(得分:2)

如果我理解正确,您需要检查数据集中是否有pronunciation。从您的第一个代码块开始,您似乎并不关心匹配来自word的内容。

因此,我认为我们可以做到:

pron_set = {tuple(pron) for word, pron in all_word_prons}
# do something to get a list of pronunciations to check
for pronunciation in pronunciation_list:
    if tuple(pronunciation) in pron_set:
        print('pronunctiation')

我们从pron_set构建tuple因为list s不可以播放(并且不能用作集合成员)。

设置查找应该比遍历列表快得多。我建议熟悉Python data structures;你永远不知道deque什么时候可以节省你很多时间。

答案 1 :(得分:0)

您是否考虑过使用此处概述的Python列表推导?

https://docs.python.org/3/tutorial/datastructures.html

在某些情况下,列表推导可能比普通的for循环更快,但它仍然执行字节码级循环。如果你不确定我的意思,请查看以下帖子:  Are list-comprehensions and functional functions faster than "for loops"?

可能值得一试,看看这会更快。