【问题标题】:How to create a dictionary of dictionaries of dictionaries in Python如何在 Python 中创建字典的字典
【发布时间】:2013-09-28 03:59:30
【问题描述】:

所以我正在学习自然语言处理课程,我需要创建一个三元语言模型来根据一些样本数据生成在一定程度上看起来“真实”的随机文本。

基本上需要创建一个“trigram”来保存各种 3 个字母的语法单词组合。我的教授暗示,这可以通过拥有一个我试图创建的字典字典来完成:

trigram = defaultdict( defaultdict(defaultdict(int)))

但是我收到一条错误消息:

trigram = defaultdict( dict(dict(int)))
TypeError: 'type' object is not iterable

我将如何创建一个 3 层嵌套字典或 int 值的字典的字典?

如果人们不知道如何回答,我猜人们会否决堆栈溢出问题。我将添加一些背景知识,以便为愿意提供帮助的人更好地解释这个问题。

此三元组用于跟踪三字模式。它们用于文本语言处理软件,几乎无处不在自然语言处理“现在想想 siri 或谷歌”。

如果我们将字典的 3 个级别指定为 dict1 dict2 和 dict3,那么解析一个文本文件并读取语句 “The boy runs” 将具有以下内容:

具有“the”键的 dict1。访问该密钥将返回包含密钥“boy”的 dict2。访问该键将返回包含键“运行”的最终 dict3,现在访问该键将返回值 1。

这象征着在这篇文章中“男孩跑”出现了1次。如果我们再次遇到它,那么我们将遵循相同的过程并将 1 增加到 2。如果我们遇到“the girl walks”,那么 dict2 的“the”键字典现在将包含另一个“girl”键,其中 dict3 的键为“walks”,值为 1,依此类推。最终在解析大量文本(并跟踪字数)之后,您将拥有一个三元组,它可以根据它们在先前解析的文本中出现的频率来确定某个起始词导致 3 个词组合的可能性.

这可以帮助您创建语法规则来识别语言,或者在我的例子中创建看起来非常像语法英语的随机生成的文本。我需要一个三层字典,因为在 3 个单词组合的任何位置都可以有另一个单词可以创建一组完全不同的组合。我尽我最大的努力解释了三元组及其背后的目的......当然我几周前刚刚讲过这门课。

现在……说了这么多。我将如何创建一个字典的字典,其基本字典在 python 中包含 int 类型的值?

trigram = defaultdict(defaultdict(defaultdict(int)))

为我抛出错误

【问题讨论】:

  • 你确实是疯狂的编码员。
  • @AlexA。就像我说的那样,是班级教授建议我们这样做。我认为这是因为我们正在使用它来构建语言模型,并且每个字典级别的键数量未知
  • 呵呵,是的,我刚刚被词典部分的词典逗乐了。对于您的用例,据我所知,这在 Python 世界中似乎是一种相当明智的方法。不要因为投反对票而灰心丧气,因为如果你问我,你的问题似乎是一个公平的问题。

标签: python dictionary


【解决方案1】:

通常,要创建一个嵌套的三元字典,已经发布的解决方案可能会起作用。如果您想扩展这个想法以获得更通用的解决方案,您可以执行以下操作之一,其中一个来自Perl's AutoVivification,另一个使用collection.defaultdict

解决方案 1:

class ngram(dict):
    """Based on perl's autovivification feature."""
    def __getitem__(self, item):
        try:
            return super(ngram, self).__getitem__(item)
        except KeyError:
            value = self[item] = type(self)()
            return value

解决方案 2:

from collections import defaultdict
class ngram(defaultdict):
    def __init__(self):
        super(ngram, self).__init__(ngram)

使用解决方案 1 的演示

>>> trigram = ngram()
>>> trigram['two']['three']['four'] = 4
>>> trigram
{'two': {'three': {'four': 4}}}
>>> a['two']
{'three': {'four': 4}}
>>> a['two']['three']
{'four': 4}
>>> a['two']['three']['four']
4

使用解决方案 2 的演示

>>> a = ngram()
>>> a['two']['three']['four'] = 4
>>> a
defaultdict(<class '__main__.ngram'>, {'two': defaultdict(<class '__main__.ngram'>, {'three': defaultdict(<class '__main__.ngram'>, {'four': 4})})})

【讨论】:

    【解决方案2】:

    我之前尝试过嵌套defaultdict,解决方案似乎是lambda 调用:

    trigram = defaultdict(lambda: defaultdict(lambda: defaultdict(int)))
    
    trigram['a']['b']['c'] += 1
    

    它不漂亮,但我怀疑嵌套字典的建议是为了高效查找。

    【讨论】:

      【解决方案3】:

      defaultdict __init__ 方法需要一个可调用的参数。传递给defaultdict 的可调用对象必须是不带参数的可调用对象,并且必须返回默认值的实例。

      嵌套defaultdict 的问题是defaultdict__init__ 带有一个参数。给 defaultdict 这个参数意味着它有一个 defaultdict 的实例,而不是包装 defaultdict 作为其 __init__ 参数的可调用参数。

      @pcoving 的lambda 解决方案将起作用,因为它创建了一个匿名函数,该函数返回一个defaultdict,该函数初始化为一个函数,该函数为字典嵌套中的每一层返回正确的类型defaultdict

      【讨论】:

        【解决方案4】:

        如果它只是提取和检索三元组,您应该尝试使用NLTK

        >>> import nltk
        >>> sent = "this is a foo bar crazycoder"
        >>> trigrams = nltk.ngrams(sent.split(), 3)
        [('this', 'is', 'a'), ('is', 'a', 'foo'), ('a', 'foo', 'bar'), ('foo', 'bar', 'crazycoder')]
        # token "a" in first element of trigram
        >>> first_a = [i for i in trigrams if i[0] == "a"]
        [('a', 'foo', 'bar')]
        # token "a" in 2nd element of trigram
        >>> second_a = [i for i in trigrams if i[1] == "a"]
        [('is', 'a', 'foo')]
        # token "a" in third element of trigram
        >>> third = [i for i in trigrams if i[2] == "a"]
        [('this', 'is', 'a')]
        # look for 2gram in trigrams
        >> two_foobar = [i for i in trigrams if "foo" in i and "bar" in i]
        [('a', 'foo', 'bar'), ('foo', 'bar', 'crazycoder')]
        # look for a perfect 3gram
        >> perfect = [i fof i in trigrams if "foo bar crazycoder".split() == i]
        [('foo', 'bar', 'crazycoder')]
        

        【讨论】:

        • 从这个意义上说,该解决方案可扩展至 >3 克,但对于大数据,您可能需要除列表理解之外的智能搜索方式。
        猜你喜欢
        • 2014-03-10
        • 2019-08-07
        • 2014-03-03
        • 2019-03-01
        • 2016-07-11
        • 2023-03-15
        • 2021-06-25
        • 2017-05-05
        • 1970-01-01
        相关资源
        最近更新 更多