我在pandas中有一个按列划分的多索引表,如下例所示:
import pandas as pd
header = pd.MultiIndex.from_product([['loc1','loc2'],
['S1','S2']],
names=['loc','S'])
df = pd.DataFrame(np.random.randint(1, high=5, size=(5,4)),
index=['a','b','c','d','e'],
columns=header)
print(df)
输出:
loc loc1 loc2
S S1 S2 S1 S2
a 4 2 2 5
b 1 4 2 4
c 2 4 2 3
d 3 4 1 2
e 4 1 3 1
我正在尝试对我使用的“ loc1”和“ loc2”执行操作
df.agg({'loc1':sum, 'loc2':np.mean})
但是出现错误: “ SpecificationError:不支持嵌套重命名器”。
预期输出是一行,其中(loc1,S1)和(loc1,S2)之和, 和(loc2,S1)和(loc2,S2)的均值
loc1 loc2
sum mean
S1 S2 S1 S2
14 15 2 3
如何使用“ agg”功能进行此计算? 有什么解决方法吗?
p.s。我知道我可以像回答Pivot table with multiple aggfunc sum and normalize one column那样来做, 但似乎有点“非pythonic”。
答案 0 :(得分:2)
您可以对DataFrame.agg
和DataFrame.stack
使用字典理解,对MultiIndex Series
使用concat
的最后Series.to_frame
并转置一行DataFrame
:
d = {'loc1':'sum','loc2':'mean'}
df1 = pd.concat({k: df[k].agg([v]).stack() for k, v in d.items()}).to_frame().T
print (df1)
loc1 loc2
sum mean
S1 S2 S1 S2
0 15.0 14.0 2.6 2.0
答案 1 :(得分:1)
如果我对您的理解正确,那么您想对每个loc
的每一行求和。我们需要在分组依据中指定level
和axis
:
df.groupby(level=0, axis=1).sum(axis=1)
loc loc1 loc2
a -0.159510 0.669699
b 0.406272 2.258626
c -0.703832 0.274719
d -1.453601 -0.480166
e 1.128587 0.504887
要分配回去,我们可以使用join
,因为索引保持不变:
dfn = df.join(df.groupby(level=0, axis=1).sum(axis=1))
(loc1, S1) (loc1, S2) (loc2, S1) (loc2, S2) loc1 loc2
a -0.540104 0.380594 0.591548 0.078151 -0.159510 0.669699
b -0.161479 0.567751 1.392222 0.866404 0.406272 2.258626
c -0.549657 -0.154175 0.447627 -0.172908 -0.703832 0.274719
d -1.811309 0.357709 0.124907 -0.605073 -1.453601 -0.480166
e 2.274189 -1.145603 0.458101 0.046786 1.128587 0.504887
请注意,您的MultiIndex列已变平。
要保持您的MultiIndex级别,我们必须创建一个称为sum
的人工级别:
dfg = df.groupby(level=0, axis=1).sum(axis=1)
dfg.columns = pd.MultiIndex.from_product([dfg.columns, ['sum']])
dfn = df.join(dfg)
loc loc1 loc2 loc1 loc2
S S1 S2 S1 S2 sum sum
a -0.540104 0.380594 0.591548 0.078151 -0.159510 0.669699
b -0.161479 0.567751 1.392222 0.866404 0.406272 2.258626
c -0.549657 -0.154175 0.447627 -0.172908 -0.703832 0.274719
d -1.811309 0.357709 0.124907 -0.605073 -1.453601 -0.480166
e 2.274189 -1.145603 0.458101 0.046786 1.128587 0.504887
最后,如果您希望按loc
对列进行排序,请使用sort_index
:
dfn.sort_index(axis=1)
loc loc1 loc2
S S1 S2 sum S1 S2 sum
a -0.540104 0.380594 -0.159510 0.591548 0.078151 0.669699
b -0.161479 0.567751 0.406272 1.392222 0.866404 2.258626
c -0.549657 -0.154175 -0.703832 0.447627 -0.172908 0.274719
d -1.811309 0.357709 -1.453601 0.124907 -0.605073 -0.480166
e 2.274189 -1.145603 1.128587 0.458101 0.046786 0.504887
答案 2 :(得分:1)
是的,似乎不支持带有pd.MultiIndex并在agg中使用dictionary的数据帧,但是,这里的解决方法将生成所需的输出。
df_sum = df.agg('sum')[['loc1']].rename('sum').to_frame().stack().reorder_levels([0,2,1])
df_avg = df.agg('mean')[['loc2']].rename('mean').to_frame().stack().reorder_levels([0,2,1])
pd.concat([df_sum, df_avg]).to_frame().T
输出:
loc loc1 loc2
sum mean
S S1 S2 S1 S2
0 11.0 15.0 3.4 2.6
答案 3 :(得分:1)
没有直接的方法可以实现所需的输出。间接方法之一是使用dict理解来构建agg字典。之后,使用此字典访问agg
,并在列和索引之间切换以获取所需的输出:
ops_dict = {'loc1':'sum', 'loc2':'mean'}
agg_dict = {(x,y): [ops_dict[x]] for x,y in df.columns}
df_agg = df.agg(agg_dict).stack([0,1]).swaplevel(0,1).sort_index(0).to_frame().T
Out[65]:
loc1 loc2
sum mean
S1 S2 S1 S2
0 14.0 15.0 2.0 3.0
或在每个pd.concat
的直接keys
和sum
上对参数mean
使用locX
df_agg = pd.concat([df[['loc1']].sum(), df[['loc2']].mean()],
keys=['sum','mean']).swaplevel(0,1).to_frame().T
或
df_agg = pd.concat([df['loc1'].sum(), df['loc2'].mean()],
keys=[('loc1','sum'), ('loc2','mean')]).to_frame().T
Out[67]:
loc loc1 loc2
sum mean
S S1 S2 S1 S2
0 14.0 15.0 2.0 3.0
答案 4 :(得分:1)
我们可以做到
new_df = (df.stack('S')
.groupby(level='S')
.agg(loc1_sum = ('loc1', 'sum'), loc2_mean = ('loc2', 'mean')))
print(new_df)
loc1_sum loc2_mean
S
S1 11 2.0
S2 10 1.8
new_df.columns = pd.MultiIndex.from_tuples(map(tuple, new_df.columns.str.split('_')))
result = new_df.unstack().to_frame().T
print(result)
loc1 loc2
sum mean
S S1 S2 S1 S2
0 11.0 10.0 2.0 1.8
答案 5 :(得分:1)
不幸的是,对列(axis = 1)上agg
的支持不如对行的完整。解决方案是通过两个agg
调用来实现。
创建聚合
o1 = df['loc1'].agg('sum').rename('sum').to_frame()
o2 = df['loc2'].agg('mean').rename('mean').to_frame()
合并聚合
result = pd.concat([o1,o2],axis=1, keys=['loc1', 'loc2'])
最后进行一些调整,以将数据转换为所需的格式
result = result.unstack().to_frame().T
结果
loc1 loc2
sum mean
S S1 S2 S1 S2
0 9.0 10.0 2.4 2.4