使用键组合合并字典

时间:2014-07-31 13:06:41

标签: python numpy dictionary hash merge

我有两个dictonaries A和B,两个都有相同的键a,b和值。这些键后面的所有3个值都是相同大小的numpy数组,但A和B之间的大小可能不同。 如果找到此链接here,但它仅适用于维度密钥: 可以看到组合a(0),b(0)作为笛卡尔空间中的坐标,值(0)作为它们的值。我有两个数据集A和B. 举个例子:

A = {'a': numpy.array([1, 1, 9, 9]),
     'b': numpy.array([0, 1, 0, 1]),
     'value': numpy.array([1, 2, 3, 4])}
B  = {'a': numpy.array([1, 1, 7, 7]),
     'b': numpy.array([0, 1, 0, 1]),
     'value': numpy.array([101, 102, 1003, 1004])}

如果两个键都相同,我需要对这些dictionarys的值求和,否则我想追加键和值。 在示例中: 两个词典共享组合键a:1和b:0,以及a:1和b:1。它们的值加起来1 + 101 = 102和2 + 102 = 104。 组合键a:9,b:0和a:9,b:1仅在字典A中 组合键a:7,b:0和a:7,b:1仅在字典B中 所以我想要这个结果

C = {'a': numpy.array([1, 1, 9, 9, 7, 7]),
     'b': numpy.array([0, 1, 0, 1, 0, 1]),
     'value': numpy.array([102, 104, 3, 4, 1003, 1004 ])}

我提出了一个解决方案,它接受字典A并通过添加或附加字典B中的内容来修改它。 因此,它首先在A中生成那些二维键组合的一维哈希键,在B中生成一个二维键组合。然后使用numpy.intersect()在两个词典中查找公共键,并将B的值添加到值A指数。然后我采用交叉点的反转并将不常见的键和值附加到字典A。

def example(A, B):
    # generate hash keys (32 bit shift because values in a and b are larger than in example)
    hash_A = map(lambda a, b: (int(a) << 32) + int(b), A['a'], A['b'])
    hash_B = map(lambda a, b: (int(a) << 32) + int(b), B['a'], B['b'])

    # intersection is now 1-dimensional and easy
    intersect = numpy.intersect1d(hash_A, hash_B)

    # common keys
    A['value'][numpy.in1d(hash_A, intersect)] += B['value'][numpy.in1d(hash_B, intersect)]

    # keys only in B and not in A
    only_in_B = numpy.in1d(hash_B, intersect, invert=True)
    if any(only_in_B):
        A['a'] = numpy.append(A['a'], B['a'][only_in_B])
        A['value'] = numpy.append(A['value'], B['value'][only_in_B])
        A['b'] = numpy.append(A['b'], B['b'][only_in_B])

    return A

但我的解决方案似乎太慢而无法使用,我想不出更快的方法。 使用的numpy.arrays有数百万个条目,这是针对几个字典组合完成的。速度是一个问题。 任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:1)

我首先将数据结构更改为:

valuesA = {(A['a'][x], A['b'][x]): A['value'][x] for x in range(len(A['a']))}

那应该给你:

{(1, 0): 1, (9, 0): 3, (1, 1): 2, (9, 1): 4}

B相同:

valuesB = {(B['a'][x], B['b'][x]): B['value'][x] for x in range(len(B['a']))}
# {(1, 0): 101, (7, 0): 1003, (1, 1): 102, (7, 1): 1004}

然后将valuesA合并到valuesB:

for key, value in valuesA.items():
    valuesB[key] = valuesB.get(key, 0) + value

结果是:

{(9, 0): 3, (7, 0): 1003, (9, 1): 4, (7, 1): 1004, (1, 0): 102, (1, 1): 104}

如果您真的需要,可以将其恢复原状:

keys = valuesB.keys()
C = {'a': [x[0] for x in keys], 'b': [x[1] for x in keys], 'value': [valuesB[x] for x in keys]}

结果是

{'a': [9, 7, 9, 7, 1, 1], 
 'b': [0, 0, 1, 1, 0, 1], 
 'value': [3, 1003, 4, 1004, 102, 104]}

Nota:如果订单确实很重要,您可以考虑使用OrderedDict而不是普通的dicts,这是一个保留广告订单的字典。