我对数据中的每组数据进行汇总统计,同时使用多个分组标准。的数据。
import pandas as pd
d = {'Fruit': ['Apple', 'Apple','Apple','Orange','Orange'],
'City': ['Rome', 'Rome', 'London', 'London','London' ],
'Value': [1, 2, 3, 4, 5 ]}
df = pd.DataFrame(data=d)
print(df)
Fruit City Value
0 Apple Rome 1
1 Apple Rome 2
2 Apple London 3
3 Orange London 4
4 Orange London 5
"groupby "命令只返回最高层的和。
keys=['Fruit','City']
df.groupby(keys).agg(Total_Value=('Value', 'sum'))
Total_Value
Fruit City
Apple London 3
Rome 3
Orange London 9
我希望将和函数也应用到较低级别。最好是将所有级别的结果显示在同一个表格中。
Total_Value
Fruit City
15
Apple 6
Orange 9
London 12
Rome 3
Apple London 3
Apple Rome 3
Orange London 9
有什么简单的方法可以生成这样一个表格吗?也许可以使用多索引函数来实现这一目的,但我不确定应该如何应用。
非常感谢
PS:在例子中,我使用了 "sum "函数。计算低级别的和相对容易。我正在寻找一个通用答案,它适用于所有函数,而不仅仅是和。(例如,平均数函数,或lambda函数等)
PS2: 类似下面的方法也可以。
Total_Value Level
Fruit City
15 0
Rome 3 1
London 12 1
Apple 6 1
Orange 9 1
Apple Rome 3 2
London 3 2
Orange London 9 2
在这种情况下,"London "的 "Total_Value "就很清楚了。不需要检查行的顺序。
你可以创建所有可能的组合 key
s,然后将其转换为dicts来替换相同的值,这里是空字符串,并传递给 DataFrame.assign
那么 concat
汇总 sum
或任何其他功能,如需要。
keys = ['Fruit','City']
#https://stackoverflow.com/a/5898031
from itertools import chain, combinations
def all_subsets(ss):
return chain(*map(lambda x: combinations(ss, x), range(0, len(ss)+1)))
dfs = [df.assign(**dict.fromkeys(x, '')) for x in all_subsets(keys)]
#swapped order of list of DataFrames
df1 = (pd.concat(dfs[::-1], sort=False)
.groupby(keys, sort=False)
.agg(Total_Value=('Value', 'sum')))
print (df1)
Total_Value
Fruit City
15
Apple 6
Orange 9
Rome 3
London 12
Apple Rome 3
London 3
Orange London 9
备用功能。
keys = ['Fruit','City']
#swapped order in range
from itertools import chain, combinations
def all_subsets(ss):
return chain(*map(lambda x: combinations(ss, x), range(len(ss)+1, -1, -1)))
dfs = [df.assign(**dict.fromkeys(x, '')) for x in all_subsets(keys)]
df = pd.concat(dfs, sort=False).groupby(keys, sort=False).agg(Total_Value=('Value', 'sum'))
print (df)
Total_Value
Fruit City
15
Rome 3
London 12
Apple 6
Orange 9
Apple Rome 3
London 3
Orange London 9
EDIT:
d = {'Fruit': ['Apple', 'Apple','Apple','Orange','Orange'],
'City': ['Rome', 'Rome', 'London', 'London','London' ],
'Value': [1, 2, 3, 4, 5 ]}
df = pd.DataFrame(data=d)
print(df)
keys = ['Fruit','City']
#https://stackoverflow.com/a/5898031
from itertools import chain, combinations
def all_subsets(ss):
return chain(*map(lambda x: combinations(ss, x), range(0, len(ss)+1)))
dfs = [df.assign(**dict.fromkeys(x, '')) for x in all_subsets(keys)]
#swapped order of list of DataFrames
df1 = (pd.concat(dfs[::-1], sort=False)
.groupby(keys, sort=False)
.agg(Total_Value=('Value', 'sum')))
最后,你可以将 MultiIndex
到 DataFrame
由 MultiIndex.to_frame
,与不等于空的字符串相似,并使用 DataFrame.dot
诀窍如果没有列的值,则通过列的值创建系列 ''
:
df2 = df1.index.to_frame()
s = df2.ne('').dot(df2.columns + ' & ').str.strip('& ').replace('', 'All')
print (s)
Fruit City
All
Apple Fruit
Orange Fruit
Rome City
London City
Apple Rome Fruit & City
London Fruit & City
Orange London Fruit & City
dtype: object
df1['level'] = s
print (df1)
Total_Value level
Fruit City
15 All
Apple 6 Fruit
Orange 9 Fruit
Rome 3 City
London 12 City
Apple Rome 3 Fruit & City
London 3 Fruit & City
Orange London 9 Fruit & City
我会这样做。
import pandas as pd
d = {'Fruit': ['Apple', 'Apple','Apple','Orange','Orange'],
'City': ['Rome', 'Rome', 'London', 'London','London' ],
'Value': [1, 2, 3, 4, 5 ]}
df = pd.DataFrame(data=d)
keys=['Fruit','City']
df_sum = df.groupby(keys).agg(Total_Value=('Value', 'sum'))
df_sub = df_sum.sum(level=0).assign(City='Fruit SubTotal').set_index('City', append=True)
df_grand = df_sum.sum().to_frame().T.rename_axis('Fruit').rename(index={0:'Grand'}).assign(City='Total').set_index('City', append=True)
df_out = pd.concat([df_sum, df_sub, df_grand])
print(df_out)
产出:
Total_Value
Fruit City
Apple London 3
Rome 3
Orange London 9
Apple Fruit SubTotal 6
Orange Fruit SubTotal 9
Grand Total 15