Самый простой способ составить список вложенных диктов - PullRequest
2 голосов
/ 17 мая 2019

Есть ли более чистый / более питонический способ суммирования содержимого списка вложенных диктов? Вот что я делаю, но я подозреваю, что может быть лучший способ:

list_of_nested_dicts = [{'class1': {'TP': 1, 'FP': 0, 'FN': 2}, 'class2': {'TP': 0, 'FP': 0, 'FN': 0}, 'class3': {'TP': 0, 'FP': 0, 'FN': 0}, 'class4': {'TP': 1, 'FP': 0, 'FN': 2}},
                        {'class1': {'TP': 1, 'FP': 0, 'FN': 2}, 'class2': {'TP': 0, 'FP': 0, 'FN': 0}, 'class3': {'TP': 0, 'FP': 0, 'FN': 0}, 'class4': {'TP': 1, 'FP': 0, 'FN': 2}},
                        {'class1': {'TP': 1, 'FP': 0, 'FN': 2}, 'class2': {'TP': 0, 'FP': 0, 'FN': 0}, 'class3': {'TP': 0, 'FP': 0, 'FN': 0}, 'class4': {'TP': 1, 'FP': 0, 'FN': 2}},
                        {'class1': {'TP': 1, 'FP': 0, 'FN': 2}, 'class2': {'TP': 0, 'FP': 0, 'FN': 0}, 'class3': {'TP': 0, 'FP': 0, 'FN': 0}, 'class4': {'TP': 1, 'FP': 0, 'FN': 2}}]

total_counts = {k:{'TP': 0, 'FP': 0, 'FN': 0} for k in list_of_nested_dicts[0].keys()}

for d in list_of_nested_dicts:
    for label,counts_dict in d.items():
        for k,v in counts_dict.items():
            total_counts[label][k] += v

print(total_counts)

(Предполагается, что все ключи одинаковы, но значения могут быть любыми целыми числами)

Ответы [ 2 ]

3 голосов
/ 17 мая 2019

Вы можете получить немного более жесткий код, используя collections (результат, аналогичный @blhsing)

import collections

counts = collections.defaultdict(collections.Counter)
for d in list_of_nested_dicts:
    for k, v in d.items():
        counts[k].update(v)

Это даст вам счетчик по умолчанию вместо счетчиков, но они ведут себя аналогично.Вы также можете явно привести их к диктовке в конце, если хотите.

{'class1': {'FN': 8, 'FP': 0, 'TP': 4},
 'class2': {'FN': 0, 'FP': 0, 'TP': 0},
 'class3': {'FN': 0, 'FP': 0, 'TP': 0},
 'class4': {'FN': 8, 'FP': 0, 'TP': 4}}

против

defaultdict(<class 'collections.Counter'>,
            {'class1': Counter({'FN': 8, 'TP': 4, 'FP': 0}),
             'class2': Counter({'TP': 0, 'FP': 0, 'FN': 0}),
             'class3': Counter({'TP': 0, 'FP': 0, 'FN': 0}),
             'class4': Counter({'FN': 8, 'TP': 4, 'FP': 0})})
2 голосов
/ 17 мая 2019

Одна вещь в вашем коде, которая выделяется как «нечистая», это то, что вы жестко программируете ключи субдиктов при инициализации total_counts. Вы можете избежать такого жесткого кодирования, используя методы dict.setdefault и dict.get, поскольку вместо этого перебираете элементы поддиктов:

total_counts = {}
for d in list_of_nested_dicts:
    for label, counts_dict in d.items():
        for k, v in counts_dict.items():
            total_counts[label][k] = total_counts.setdefault(label, {}).get(k, 0) + v
...