用键组合合并字典



我有两个字典A和B,它们都有相同的键A, B和value。这些键后面的所有3个值都是相同大小的numpy数组,但大小在A和B之间可能不同。如果在这里找到这个链接,但它只适用于一维键:我们可以把a(0),b(0)看成笛卡尔空间中的坐标,把value(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])}

如果两个键相同,我需要对这些字典的值求和,否则我想将键和值附加在一起。在这个例子中:两个字典共享键组合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。所使用的数组有数百万个条目,这是针对几种字典组合完成的。速度是个问题。

我将从改变数据结构开始:

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]}

注意:如果顺序确实很重要,您可以考虑使用OrderedDict而不是普通字典,这是一种保留插入顺序的字典。

最新更新