【问题标题】:Python 3 - efficient lookups with large listsPython 3 - 大列表的高效查找
【发布时间】:2015-05-20 02:38:25
【问题描述】:

我正在使用 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']]]

这些是单词、发音(发音)对。我操纵了prons(也许将'G'换成'T')并检查这是否是一个词。我通过使用这个函数来做到这一点:

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 中进行这种查找(匹配列表)的最快方法是什么?

【问题讨论】:

  • 是否有任何特殊原因您没有将发音转换为tuple(以便您可以散列它们)然后将它们扔进set?或者dict,如果您仍想将它们映射到原始单词。
  • 也就是说,这只是duplicate of this吗?
  • 没有。这是完全正确的。我想我不认为字典会快得多。我错了。它们的速度要快得多(1000 次查找不到一秒......)。将发音转换为元组,然后将它们作为键并使用 .get(pronunciation, False) 进行某种错误报告。奇迹般有效。谢谢。

标签: python nltk


【解决方案1】:

如果我理解正确,您想检查一下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')

我们从tuples 构造pron_set,因为lists 不可散列(也不能用作集合成员)。

设置查找应该比遍历列表快得多。我建议熟悉Python data structures;您永远不知道deque 何时可以为您节省大量时间。

【讨论】:

    【解决方案2】:

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-03
      • 1970-01-01
      • 1970-01-01
      • 2018-12-09
      • 2020-01-16
      • 1970-01-01
      • 1970-01-01
      • 2013-10-17
      相关资源
      最近更新 更多