使用多索引/分组对象"按组"对值进行排序,而不会破坏索引级别

  • 本文关键字:索引 排序 对象 按组 pandas
  • 更新时间 :
  • 英文 :


是否可以按每组的和的计数值进行排序?不突破指数水平?我注释掉的两次尝试都会排序,但会破坏索引级别。

#DataFrame
ff = pd.DataFrame([('P1', 17, 'male'),
('P2', 10, 'female'),
('P3', 10, 'male'),
('P4', 19, 'female'),
('P5', 10, 'male'),
('P6', 12, 'male'),
('P7', 12, 'male'),
('P8', 15, 'female'),
('P9', 15, 'female'),
('P10', 10, 'male')],
columns=['Name', 'Age', 'Sex'])
# Attempts
(
ff
.groupby(['Age', 'Sex'])
.agg(**{
'Count': pd.NamedAgg(column="Name", aggfunc='count'),
'Who': pd.NamedAgg(column="Name", aggfunc=lambda x: ', '.join([i for i in x]))})
#     .sort_values('Count')           <- this breaks the index level
#     .sort_values(['Count', 'Age'])  <- this too breaks the index level
)

原始数据:

p2p3、p5 p10p6、p7 td>p8,票数p4

可以通过DataFrame.unstack重塑,如果存在,则通过Sex值之和排序索引,然后通过DataFrame.stack重塑:

df1 = df.unstack()
df1 = df1.sort_index(key=df1.sum(axis=1, numeric_only=True).get).stack().astype(df.dtypes)
print (df1)
Count          Who
Age Sex                       
17  male        1           P1
19  female      1           P4
12  male        2       P6, P7
15  female      2       P8, P9
10  female      1           P2
male        3  P3, P5, P10

另一个想法是用GroupBy.transform对两个值求和:

df['tmp'] = df.groupby('Age')['Count'].transform('sum')
df1 = df.sort_values(['tmp','Age']).drop('tmp', axis=1)
print (df1)
Count          Who
Age Sex                       
17  male        1           P1
19  female      1           P4
12  male        2       P6, P7
15  female      2       P8, P9
10  female      1           P2
male        3  P3, P5, P10

编辑:一行解决方案是:

df = (
ff
.groupby(['Age', 'Sex'])
.agg(**{
'Count': pd.NamedAgg(column="Name", aggfunc='count'),
'Who': pd.NamedAgg(column="Name", aggfunc=', '.join)})

.assign(tmp = lambda x: x.groupby('Age')['Count'].transform('sum'))
.sort_values(['tmp','Age'])
.drop('tmp', axis=1))
print (df)
Count          Who
Age Sex                       
17  male        1           P1
19  female      1           P4
12  male        2       P6, P7
15  female      2       P8, P9
10  female      1           P2
male        3  P3, P5, P10

好了。

让我们将temp变量保留在data中。

data = ff.groupby(['Age', 'Sex']).agg(**{
'Count': pd.NamedAgg(column="Name", aggfunc='count'),
'Who': pd.NamedAgg(column="Name", aggfunc=lambda x: ', '.join([i for i in x]))})

您可以通过apply函数在每个组中编写一个自定义函数来做您想做的事情。

例如。

data.groupby("Age", group_keys=False).apply(lambda x: x.sort_values("Count", ascending=False))
Count          Who
Age Sex                       
10  male        3  P3, P5, P10
female      1           P2
12  male        2       P6, P7
15  female      2       P8, P9
17  male        1           P1
19  female      1           P4

或者改成ascending order

data.groupby("Age", group_keys=False).apply(lambda x: x.sort_values("Count", ascending=False))
Count          Who
Age Sex                       
10  female      1           P2
male        3  P3, P5, P10
12  male        2       P6, P7
15  female      2       P8, P9
17  male        1           P1
19  female      1           P4

或者如果你想按每一级多索引排序。你可以这样做。

您可以通过在sort_index函数中添加level参数来对索引进行排序。

例如:

  1. data.sort_index(level=0, ascending=True)

对第一个索引按升序排序。

Count          Who
Age Sex                       
19  female      1           P4
17  male        1           P1
15  female      2       P8, P9
12  male        2       P6, P7
10  male        3  P3, P5, P10
female      1           P2
  1. data.sort_index(level=[0,1], ascending=[False, True])

第一个索引按升序排序,第二个索引按降序排序。

Count          Who
Age Sex                       
19  female      1           P4
17  male        1           P1
15  female      2       P8, P9
12  male        2       P6, P7
10  female      1           P2
male        3  P3, P5, P10

顺便说一下。

breaking index level不是一个特殊的结果。它只是一个显示优化

例如。

你可以自己创建一个:

pd.DataFrame({"a":[1,2,3,4,5]}, index=pd.MultiIndex.from_arrays([[10,10,20,10,10],['F','M','F','M','F']],names=['A','B']))
a
A  B   
10 F  1
M  2
20 F  3
10 M  4
F  5

最新更新