#python #python-3.x #pandas #dataframe #dictionary
Вопрос:
Ниже приведен мой df
:
In [425]: df
Out[425]:
a b c d
0 abc 1 1 True
1 abd 1 1 False
2 abe 1 2 False
3 abf 1 2 True
4 abg 2 2 True
Я хочу сгруппироваться по столбцам b
c
и создать диктант с оставшимися именами столбцов и их значениями.
Ожидаемый Результат:
[
{
"b": 1,
"c": 1,
"attr":[
{
"a": "abc",
"d": True
},
{
"a": "abd",
"d": False
}
]
},
{
"b": 1,
"c": 2,
"attr":[
{
"a": "abe",
"d": False
},
{
"a": "abf",
"d": True
}
]
},
{
"b": 2,
"c": 2,
"attr":[
{
"a": "abg",
"d": True
}
]
}
]
Моя попытка:
In [423]: df.set_index(['b', 'c']).agg(list, 1).to_dict()
Out[423]: {(1, 1): ['abd', False], (1, 2): ['abf', True], (2, 2): ['abg', True]}
Я могу группировать и создавать диктант, но не знаю, как добавить к нему имена столбцов.
Комментарии:
1. Хорошая фотография в профиле 😉
2. Хе-хе. спасибо @jezrael
Ответ №1:
Понимание
[dict(b=b, c=c, attr=d.to_dict('records'))
for (b, c), d in df.set_index(['b', 'c']).groupby(['b', 'c'])]
[{'b': 1, 'c': 1, 'attr': [{'a': 'abc', 'd': True}, {'a': 'abd', 'd': False}]},
{'b': 1, 'c': 2, 'attr': [{'a': 'abe', 'd': False}, {'a': 'abf', 'd': True}]},
{'b': 2, 'c': 2, 'attr': [{'a': 'abg', 'd': True}]}]
Комментарии:
1. Это здорово. Спасибо. 1.
Ответ №2:
Используйте пользовательскую лямбда-функцию с DataFrame.to_dict
помощью in GroupBy.apply
:
d = (df.groupby(['b','c'])[['a','d']]
.apply(lambda x: x.to_dict('records'))
.reset_index(name='attr')
.to_dict('records'))
print (d)
[{'b': 1, 'c': 1, 'attr': [{'a': 'abc', 'd': True},
{'a': 'abd', 'd': False}]},
{'b': 1, 'c': 2, 'attr': [{'a': 'abe', 'd': False},
{'a': 'abf', 'd': True}]},
{'b': 2, 'c': 2, 'attr': [{'a': 'abg', 'd': True}]}]
Альтернатива, если имеется несколько столбцов:
d = (df.set_index(['b','c'])
.groupby(['b','c'])
.apply(lambda x: x.to_dict('records'))
.reset_index(name='attr')
.to_dict('records'))
print (d)
Производительность в огромном фрейме данных со многими группами:
np.random.seed(123)
N = 1000000
L1 = list('abcdefghijklmno')
L = np.random.randint(100,size=N)
df = pd.DataFrame({'a': np.random.choice(L1, N),
'b': np.random.choice(L, N),
'c':np.random.choice(L, N),
'd':np.random.choice([True, False], N),})
print (df)
In [51]: %timeit [dict(b=b, c=c, attr=d.to_dict('records')) for (b, c), d in df.set_index(['b', 'c']).groupby(['b', 'c'])]
6.01 s ± 247 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [53]: %timeit (df.groupby(['b','c'])[['a','d']].apply(lambda x: x.to_dict('records')).reset_index(name='attr').to_dict('records'))
4.79 s ± 137 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)