Python defaultdict与dict元素初始化

Python defaultdict与dict元素初始化,python,dictionary,defaultdict,Python,Dictionary,Defaultdict,我试图优化脚本的性能,该脚本在词典中为给定的每个单词查找相似的单词 每个唯一的单词将被拆分为字母n-gram,对于每个n-gram,词典将返回包含相同字母n-gram的单词列表。然后,此列表中的每个单词都作为键添加到字典中,其值递增1。这给了我一本字典,里面有相似的单词和相应的频率分数 word_dict = {} get = word_dict.get for letter_n_gram in word: for entry in lexicon[n_gram]: wo

我试图优化脚本的性能,该脚本在词典中为给定的每个单词查找相似的单词

每个唯一的单词将被拆分为字母n-gram,对于每个n-gram,词典将返回包含相同字母n-gram的单词列表。然后,此列表中的每个单词都作为键添加到字典中,其值递增1。这给了我一本字典,里面有相似的单词和相应的频率分数

word_dict = {}
get = word_dict.get
for letter_n_gram in word:
    for entry in lexicon[n_gram]:
        word_dict[entry] = get(entry, 0) + 1
这个实现是可行的,但是通过切换
集合的
dict
。defaultdict
,脚本可以运行得更快

word_dd = defaultdict(int)
for letter_n_gram in word:
    for entry in lexicon[n_gram]:
        word_dd[entry] += 1
没有其他代码被更改


我的印象是,两个代码段(最重要的是分数添加)的工作方式应该完全相同,即,如果键存在,则将其值增加1,如果不存在,则创建键并将值设置为1

然而,在运行新代码之后,一些键的值为0,我发现这在逻辑上是不可能的

我的
defaultdict
功能的逻辑或知识是否有缺陷?如果没有,如何将
word\u dd
中的任何值设置为0

编辑:我也非常确定脚本的任何其他部分都不会扭曲这些结果,因为我在显示代码后立即使用以下方法测试字典:

for item in word_dd.iteritems():
    if item[1] == 0:
        print "Found zero value element"
        break

当您访问
defaultdict
中的密钥时,如果该密钥不存在,则会自动创建该密钥。因为我们有
int
作为默认的工厂函数,它创建键并给出默认值0

from collections import defaultdict
d = defaultdict(int)
print d["a"]
# 0
print d
# defaultdict(<type 'int'>, {'a': 0})
对钥匙的任何项目访问都将实现以下价值:

>>> from collections import defaultdict
>>> d = defaultdict(int)
>>> d['foo']
0
使用安全壳测试是否存在:

>>> 'bar' in d
False
>>> 'foo' in d
True
由于您正在计算n克,您可能还想看看:

其中
Counter.update()
将更新
词典[n_gram]
表达式返回的所有条目的计数


defaultdict(int)
Counter()
对象自动实现值,默认为整数
0
,唉,我在代码中发现了错误

由于在我的输入集中有许多具有相同测试单词的后续单词n-gram,因此我只为每个唯一测试单词创建一次类似单词的词典

然后,此词典用于其他目的,并对密钥进行多次测试。当然,如果字典是
collections.defaultdict
,并且默认工厂未设置为
None
,则这可以创建零值元素

然而,对零值元素的测试是在每个主循环中完成的——因此,要查找在前一个循环中创建的零值元素

将测试代码缩进适当的部分后,结果与预期的一样-创建后立即没有零值元素


我想为我的问题的错误和不完整的构造向所有人道歉-其他人不可能找到错误。

什么键的值为0?您确定这些键已经在字典中了吗?如何测试这些值?任何密钥访问都将创建密钥;因此,
word\u dd['nonecoke']
不会赋值,但会为您创建值。测试问题中添加的值您对
defaultdict
的理解似乎很好:您发布的代码不可能在word\u dd.values()中以
0结尾。您确定在您发布的两段代码之间没有任何涉及
word\u dd
的代码吗?此外,当默认值计算起来很昂贵时,defaultdict的运行速度将明显快于dict.get/dict.setdefault,而常数int肯定不是。之所以在这里考虑,是因为它使代码更简单,而不是更快。这是 Debug语句优化的全部要点。在另一种情况下,它消除了
get(entry,0)
的开销。请编辑我的问题reiterate@Deutherius如果
1
不在DDCT中,则将创建它并使用默认值0。我在回答中解释了这种行为。请检查。我的印象是,
word\u ddict.iteritems()
将返回字典中现有项的迭代器-我测试循环中的
是(键、值)的元组,因此
1
,它是索引,不是字典查询。@Deutherius哦,对不起,我误解了。无论如何,你不是在检查值,而是键,对吗?它们可以有零。你能展示一个实际数据的样本来重现这个问题吗?根据我的观点,我认为我没有错误地测试零值的存在
word\u dd.iteritems()
不应该创建任何元素。我一定会查到
收藏。柜台
,谢谢。@Deutherius:不,
。iteritems()
不会。不过,您在问题中发布的代码也不会出现。@Deutherius:您在字典中拥有
0
值的唯一方法是访问键(因此
dictionary[key]
字典中尚未定义键的任何位置),或者直接分配
0
(通过赋值、扩充赋值或
.update()
)。
>>> 'bar' in d
False
>>> 'foo' in d
True
from collections import Counter

word_counter = Counter()
for letter_n_gram in word:
    word_counter.update(lexicon[n_gram])