Pandas dataframe to dict of dict

Учитывая следующий кадр данных pandas:

  ColA ColB  ColC
0   a1    t     1
1   a2    t     2
2   a3    d     3
3   a4    d     4

Я хочу получить словарь словаря.

Но мне удалось создать только следующее:

d = {t : [1, 2], d : [3, 4]}

от:

d = {k: list(v) for k,v in duplicated.groupby("ColB")["ColC"]}

Как я мог получить диктовку dict:

dd = {t : {a1:1, a2:2}, d : {a3:3, a4:4}}

Ответ 1

Вы можете сделать это с помощью groupby + apply шаг заранее.

dd = df.set_index('ColA').groupby('ColB').apply(
    lambda x: x.ColC.to_dict()
).to_dict()

Или, с пониманием дикта:

dd = {k : g.ColC.to_dict() for k, g in df.set_index('ColA').groupby('ColB')}

print(dd)
{'d': {'a3': 3, 'a4': 4}, 't': {'a1': 1, 'a2': 2}}

Ответ 2

Цель этого ответа - показать, что есть прямой способ сделать это с помощью простой итерации и инструментов из стандартной библиотеки.

Часто мы выполняем много преобразований в Pandas DataFrame, где каждое преобразование вызывает конструкцию нового объекта Pandas. Время от времени это может быть интуитивной прогрессией и иметь прекрасный смысл. Однако есть моменты, когда мы забываем, что мы можем использовать более простые инструменты. Я считаю, что это один из тех времен. Мой ответ по-прежнему использует Pandas, поскольку я использую метод itertuples.

from collections import defaultdict

d = defaultdict(dict)

for a, b, c in df.itertuples(index=False):
    d[b][a] = c

d = dict(d)

d

{'t': {'a1': 1, 'a2': 2}, 'd': {'a3': 3, 'a4': 4}}

Небольшая альтернатива. Поскольку кортежи, которые мы итерируем, называются кортежами, мы можем получить доступ к каждому элементу по имени столбца, который он представляет.

from collections import defaultdict

d = defaultdict(dict)

for t in df.itertuples():
    d[t.ColB][t.ColA] = t.ColC

d = dict(d)

d

{'t': {'a1': 1, 'a2': 2}, 'd': {'a3': 3, 'a4': 4}}