首页 > 解决方案 > 不清楚为什么带有单组的 groupby 会产生行 DataFrame

问题描述

这是对 a 的两个groupby操作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

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

ans2无论分组系列中的组数如何,如何确保输出始终如一?有没有比这更快/更好的方法

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

标签: pythonpandas

解决方案


我认为最简单的方法是避免.apply()重新组合时确实会做奇怪的事情。这可能是因为这个函数的语义太模糊了。您可以返回任何内容,pandas 会尽力猜测您的意思

如果您希望与适用于整个子数据框的函数的结果一致,您最好自己运行该函数:

>>> pd.concat({n: (lambda x: x.a * x.b.iloc[0])(g) for n, g in d.groupby(grp1)})
1  0    1
   1    2
   2    3
   3    4
   4    5
   5    6
Name: a, dtype: int64
>>> pd.concat({n: (lambda x: x.a * x.b.iloc[0])(g) for n, g in d.groupby(grp2)})
1  0     1
   1     2
   2     3
2  3    12
   4    15
   5    18
Name: a, dtype: int64

现在我建议改为使用具有明确定义的返回形状的函数。这里.transform()可能有用:

>>> d.groupby(grp1)['b'].transform('first')
0    1
1    1
2    1
3    1
4    1
5    1
Name: b, dtype: int64
>>> d.groupby(grp2)['b'].transform('first')
0    1
1    1
2    1
3    3
4    3
5    3
Name: b, dtype: int64

这是一个如何用于相同计算的示例:

>>> ans1 = d.copy()
>>> ans1['a'] *= d.groupby(grp1)['b'].transform('first')
>>> ans1
   a  b
0  1  1
1  2  2
2  3  4
3  4  3
4  5 -1
5  6  5
>>> ans2 = d.copy()
>>> ans2['a'] *= d.groupby(grp2)['b'].transform('first')
>>> ans2
    a  b
0   1  1
1   2  2
2   3  4
3  12  3
4  15 -1
5  18  5

推荐阅读