不清楚为什么带有单个组的 groupby 会生成行 DataFrame

d.b*_*d.b 9 python pandas

这是groupby对 a 的两个操作pandas.DataFrame

import pandas


d = pandas.DataFrame({"a": [1, 2, 3, 4, 5, 6],
                      "b": [1, 2, 4, 3, -1, 5]})

grp1 = pandas.Series([1, 1, 1, 1, 1, 1])
ans1 = d.groupby(grp1).apply(lambda x: x.a * x.b.iloc[0])

grp2 = pandas.Series([1, 1, 1, 2, 2, 2])
ans2 = d.groupby(grp2).apply(lambda x: x.a * x.b.iloc[0])

print(ans1.reset_index(drop=True))
# a  0  1  2  3  4  5
# 0  1  2  3  4  5  6

print(ans2.reset_index(drop=True))
# 0     1
# 1     2
# 2     3
# 3    12
# 4    15
# 5    18
# Name: a, dtype: int64
Run Code Online (Sandbox Code Playgroud)

我想要的输出格式为ans2. 如果分组系列有多个组(如图所示grp2),则输出格式没有问题。但是,当分组系列只有一个组时(如 中所示grp1),输出是DataFrame具有单行的 a。为什么是这样?

如何确保ans2无论分组系列中有多少组,输出始终都是一样的?有没有比以下更快/更好的方法

  1. 检查输出是否为 DataFrame 并强制转换为 Series
  2. 检查分组系列是否只有一组并避免groupby这种情况

tih*_*hom 2

一个简单的解决方案是返回DataFramefrom apply

import pandas


d = pandas.DataFrame({"a": [1, 2, 3, 4, 5, 6],
                      "b": [1, 2, 4, 3, -1, 5]})


grp1 = pandas.Series([1, 1, 1, 1, 1, 1])


ans1 = d.groupby(grp1).apply(lambda x: x[['a']] * x.b.iloc[0])

grp2 = pandas.Series([1, 1, 1, 2, 2, 2])
ans2 = d.groupby(grp2).apply(lambda x: x[['a']] * x.b.iloc[0])

print(ans1.reset_index(drop=True))
#    a
# 0  1
# 1  2
# 2  3
# 3  4
# 4  5
# 5  6

print(ans2.reset_index(drop=True))
#     a
# 0   1
# 1   2
# 2   3
# 3  12
# 4  15
# 5  18
Run Code Online (Sandbox Code Playgroud)

要理解原因,函数的文档apply会很有帮助。当给定的函数apply返回 a时Series,它们将转换为一行,最终输出是 a,DataFrame每组一行。所以 的行为grp1实际上是预期的。

这就引出了一个问题,为什么第二种情况使用grp2return a Series。我认为这是因为两组返回的Series索引值不同。因此,这两个组的结果被附加在具有多级索引的单行中(如下所示)。

d = pandas.DataFrame({"a": [1, 2, 3, 4, 5, 6],
                      "b": [1, 2, 4, 3, -1, 5]})

grp2 = pandas.Series([1, 1, 1, 2, 2, 2])
def func(x):
    z= x.a * x.b.iloc[0]
    print(z.index)
    return z
ans2 = d.groupby(grp2).apply(func)
# Int64Index([0, 1, 2], dtype='int64')
# Int64Index([3, 4, 5], dtype='int64')

print(ans2)
# 1  0     1
#    1     2
#    2     3
# 2  3    12
#    4    15
#    5    18
# Name: a, dtype: int64
Run Code Online (Sandbox Code Playgroud)