【问题标题】:Comprehensions to combine two dicts and create value lists结合两个dicts并创建值列表的理解
【发布时间】:2017-08-03 21:02:32
【问题描述】:

我有两个字典,每个字典都用于计算两个列表中唯一字符串的实例数。除了有数千个条目之外,它们看起来像这样:

d1 = {'pig':10, 'cow':40, 'sheep':50}
d2 = {'pig':40, 'cow':20, 'sheep':10, 'tiger':30}

d1_total = 100    #sum of the dictionary values
d2_total = 100    #my actual dictionaries have different sums

我希望用出现在 d1 和 d2 中的键来填充新字典。我希望每个键的值是一个列表 v 具有以下内容:

v[0] = d2_value/d1_value    #fold change
v[1] = d1_value/d1_total    #fraction of the total count (d1)
v[2] = d2_value/d2_total    #fraction of the total count (d2)

所以最终结果是:

d_new = {'pig':[4, 0.1, 0.4], 'cow':[0.5, 0.4, 0.2], 'sheep':'[0.2, 0.5, 0.1]}

我编写了以下代码,它可以运行,但是由于字典很大,执行时间太长:

def common_keys(d1, d2, d1_total, d2_total):
    common = {}
    for x, y in d1.iteritems():
        for k, v in d2.iteritems():

            d1_frac = y/d1_total
            d2_frac = v/d2_total
            fold_change = d2_frac/d1_frac

            if x == k:
                common[x] = [fold_change, d1_frac, d2_frac]
    return commmon

我觉得我应该使用字典推导来提高速度,但我不知道如何从两个字典等中收集值......类似于:

common = {k:[???, (v/d1_total), (???/d2_total)] for k, v in d1.items() if k in d2.items()}

你能帮我正确地写这个吗?非常感谢您的帮助。我终于开始思考字典理解,但是当组合字典并将值修改为这样的列表时,事情变得令人困惑。

【问题讨论】:

    标签: python merge dictionary-comprehension


    【解决方案1】:

    你不需要理解来提高这里的速度。就个人而言,我会避免它,因为列表创建变得过于混乱并且变得难以阅读。你需要的是一个更好的算法。具体来说,您可以通过执行键查找而不是遍历 d2 来查找公共项来更好地做到这一点:

    def common_keys(d1, d2, d1_total, d2_total):
        common = {}
        for x, y in d1.iteritems():
            try:
                v = d2[x]
            except KeyError:
                continue
    
            d1_frac = y/d1_total
            d2_frac = v/d2_total
            fold_change = d2_frac/d1_frac
    
            common[x] = [fold_change, d1_frac, d2_frac]
        return commmon
    

    这样做可以摆脱内部循环,从而节省大量时间。

    【讨论】:

    • 这太好了,谢谢。我知道循环中的循环是不必要且低效的,但我不知道有任何其他方法可以做到这一点。我同意这种结构比理解更具可读性。
    • 谈到 Python 代码优化 - 我会看一下 drive.google.com/file/d/0Bw5McUt95YdeMlNiX2VSR1lFRHM/view,在那里您会看到分析后的第一步是了解您的瓶颈在哪里(第 14 页),正如@mgilson 所建议的那样 - 试图找到更好的算法。
    【解决方案2】:

    您可以在 Python 3 中取关键交集并执行以下操作:

    d_new = {k: [d2[k]/d1[k], d1[k]/d1_total, d2[k]/d2_total] 
                                              for k in d1.keys() & d2.keys()}
    

    在 Python 2 中与set(d1).intersection(d2)d1.viewkeys() & d2.viewkeys() 相交。

    另外,请注意 Python 2 中使用运算符 / 对两个整数操作数的取舍。

    您可以使用d2[k]/float(d1[k]), ... 来避免楼层划分。

    【讨论】:

    • 在python2.7中你会使用d1.viewkeys() & d2.viewkeys()
    • @mgilson 谢谢,已添加。
    【解决方案3】:

    您可以使用条件字典理解。遍历d1中的每个键并检查它是否在d2

    d1_total = float(sum(d1.values()))
    d2_total = float(sum(d2.values()))
    >>> {k: [d2[k] / float(d1[k]), d1[k] / d1_total, d2[k] / d2_total] 
         for k in d1 if k in d2}
    {'cow': [0.5, 0.4, 0.2], 'pig': [4.0, 0.1, 0.4], 'sheep': [0.2, 0.5, 0.1]}
    

    时机

    d1 = {n: 'a' for n in range(100000)}
    d2 = {n: 'b' for n in range(50000, 150000)}
    
    >>> %timeit [k for k in d1 if k in d2]
    100 loops, best of 3: 10.1 ms per loop
    
    >>> %timeit [k for k in d1.viewkeys() & d2.viewkeys()]
    100 loops, best of 3: 10.5 ms per loop
    

    时间应该差不多。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-10
      • 1970-01-01
      • 2021-10-20
      • 1970-01-01
      • 1970-01-01
      • 2020-10-12
      相关资源
      最近更新 更多