Python pandas группировать по нескольким столбцам, затем сворачивать

В Python у меня есть pandas DataFrame, подобный следующему:

Item | shop1 | shop2 | shop3 | Category
------------------------------------
Shoes| 45    | 50    | 53    | Clothes
TV   | 200   | 300   | 250   | Technology
Book | 20    | 17    | 21    | Books
phone| 300   | 350   | 400   | Technology

Где shop1, shop2 и shop3 - это затраты на каждый предмет в разных магазинах. Теперь мне нужно вернуть DataFrame после очистки данных, например:

Category (index)| size| sum| mean | std
----------------------------------------

где size - количество элементов в каждой категории, а сумма, средняя и std связаны с теми же функциями, которые применяются к 3 магазинам. Как я могу выполнять эти операции с помощью шаблона split-apply-comb (groupby, aggregate, apply,...)?

Может кто-нибудь помочь мне? Я схожу с ума от этого... спасибо!

Ответ 1

вариант 1
используйте agg ← ссылка на docs

agg_funcs = dict(Size='size', Sum='sum', Mean='mean', Std='std')
df.set_index(['Category', 'Item']).stack().groupby(level=0).agg(agg_funcs)

                  Std   Sum        Mean  Size
Category                                     
Books        2.081666    58   19.333333     3
Clothes      4.041452   148   49.333333     3
Technology  70.710678  1800  300.000000     6

вариант 2
больше за меньшее
используйте describe ← ссылка на docs

df.set_index(['Category', 'Item']).stack().groupby(level=0).describe().unstack()

            count        mean        std    min    25%    50%    75%    max
Category                                                                   
Books         3.0   19.333333   2.081666   17.0   18.5   20.0   20.5   21.0
Clothes       3.0   49.333333   4.041452   45.0   47.5   50.0   51.5   53.0
Technology    6.0  300.000000  70.710678  200.0  262.5  300.0  337.5  400.0

Ответ 2

df.groupby('Category').agg({'Item':'size','shop1':['sum','mean','std'],'shop2':['sum','mean','std'],'shop3':['sum','mean','std']})

Или, если вы хотите это во всех магазинах, тогда:

df1 = df.set_index(['Item','Category']).stack().reset_index().rename(columns={'level_2':'Shops',0:'costs'})
df1.groupby('Category').agg({'Item':'size','costs':['sum','mean','std']})

Ответ 3

Если я правильно понимаю, вы хотите рассчитать совокупные показатели для всех магазинов, а не для каждого отдельно. Для этого вы можете сначала stack ваш файл данных, а затем группу Category:

stacked = df.set_index(['Item', 'Category']).stack().reset_index()
stacked.columns = ['Item', 'Category', 'Shop', 'Price']
stacked.groupby('Category').agg({'Price':['count','sum','mean','std']})

В результате получается

           Price                             
           count   sum        mean        std
Category                                     
Books          3    58   19.333333   2.081666
Clothes        3   148   49.333333   4.041452
Technology     6  1800  300.000000  70.710678