复制groupby应用行为,返回序列(输出类型不一致)

我对pandas groupby apply函数返回序列时的行为感到好奇

当序列的长度不同时,它返回一个多索引序列

[1]on

:将熊猫作为pd导入
At[2]on,df1=pd.DataFrame({'state':list(“AABBB”),
…:“城市”:列表(“vwxyz”)})
In[3]:df1
Output[3]:
城邦
0伏A
1瓦
2 x B
3 y B
4 z B
At[4]on:定义f(x):
…:返回pd.系列(x['city']值,索引=范围(len(x)))
...:
[5]on:df1.groupby('state').apply(f)
Output[5]:
状态
零伏
1瓦
B 0 x
1年
2 z
数据类型:对象

这将返回一个系列对象

但是,如果每个序列都有相同的长度,那么它会将其旋转到一个数据帧中

[6]on

:df2=pd.DataFrame({'state':list(“AAABBB”),
…:“城市”:列表(“uvwxyz”)})
In[7]:df2
Output[7]:
城邦
0 u A
1伏A
2瓦A
3 x B
4 y B
5 z B
[8]on:df2.groupby('state').apply(f)
Output[8]:
0  1  2
状态
u v w
B x y z

这真的是我们想要的行为吗?如果我们以这种方式使用apply,是否要检查返回类型?或者在apply中是否有我不欣赏的选项

如果您好奇,在我的实际用例中,返回的序列的长度将与组的长度相同。这似乎是transform的理想情况,但我发现在大型数据集上使用apply返回序列实际上要快一个数量级。这可能是另一个话题

编辑:大致根据冻糕的答案,我们当然可以这样做:

X=df.groupby('state')。应用(f)
如果不存在(X,pd系列):
X=X.stack()
X

这将为df=df1df=df2提供相同的输出类型。我想我只是在问,这是否是处理这件事的正常方式或首选方式

本质上,数据帧由等长序列组成(技术上是序列对象的字典容器)。如split apply combine docs中所述,运行groupby()涉及以下一项或多项

  • 根据某些标准将数据拆分为组
  • 将函数独立应用于每个组
  • 将结果合并到数据结构中

请注意,这并不是说总是生成数据帧,而是一个通用的数据结构。因此,groupby()操作可以向下转换为一个系列,或者如果给定一个系列作为输入,则可以向上转换为数据帧

对于第一个数据帧,您运行不相等的分组(或不相等的索引长度)强制执行序列返回,而在“组合”处理中,该序列返回不能充分生成数据帧。由于数据帧不能组合不同长度的序列,因此会生成多索引序列。您可以在定义函数中的print语句中看到这一点,其中state==A组的长度为2,而B组的长度为3

def(x):
打印(x)
返回pd.系列(x['city'].值,索引=范围(len(x)))
s1=df1.groupby('state')。应用(f)
打印(s1)
#城邦
#0伏A
#1瓦
#城邦
#0伏A
#1瓦
#城邦
#2 x B
#3 y B
#4 z B
#陈述
#零伏
#1瓦
#B 0 x
#1年
#2 z
#数据类型:对象

但是,您可以通过重置索引,从而调整其层次结构来操纵多索引系列结果:

df=df1.groupby('state').apply(f).reset_index()
打印(df)
#州级_1 0
#0 A 0 v
#1 A 1 w
#2B0X
#3b1y
#4B2Z

但和您的需求更相关的是unstack(),它旋转一级索引标签,生成一个数据帧。考虑 fILNA()以填写无< 结果>

df=df1.groupby(’state’).apply(f).unstack()
打印(df)
# 0 1 2
#陈述
#没有
#B x y z

发表评论