pandas中groupby使用的摸索

pandas中groupby使用的摸索

关于groupby的“split-apply-combine”的特性,请查阅官方文档及其他资料。这里只记录下自己在解决问题中遇到的问题。

问题

数据分组后,使用2列数据的运算结果,生成新的一列数据。

  • 假设数据为,
>>> df
    a   b   c   d group
0  94  32  37  13    G1
1  87  95  24  77    G2
2   6  74  68  64    G3
3  36  17  83   4    G2
4  35  61  20   0    G1
  • 用了groupby后的输出结果是DataFrameGroupBy类型,
>>> df.groupby("group")
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000026D9B10F448>
  • 先看下不同操作时候输出的结果又何不同,
    累加操作,每组后每行的结果不同,
>>> df.groupby("group")["a","c"].cumsum()
     a    c
0   94   37
1   87   24
2    6   68
3  123  107
4  129   57

求和操作,分组后每组结果一致,就是所谓的聚合操作,

>>> df.groupby("group")["a","c"].sum()
         a    c
group
G1     129   57
G2     123  107
G3       6   68
  • 假设在聚合操作的情况下,取一列数据操作,把结果写入新的一列,
>>> df.groupby("group")["a"].sum()
group
G1    129
G2    123
G3      6
Name: a, dtype: int32

>>> df["sum_a"] = df.groupby("group")["a"].sum()
>>> df
    a   b   c   d group  sum_a
0  94  32  37  13    G1    NaN
1  87  95  24  77    G2    NaN
2   6  74  68  64    G3    NaN
3  36  17  83   4    G2    NaN
4  35  61  20   0    G1    NaN

操作不符合预期!

再换一种方式,

>>> df["sum_a"] = df.groupby("group")["a"].apply(lambda x: sum(x))
>>> df
    a   b   c   d group  sum_a
0  94  32  37  13    G1    NaN
1  87  95  24  77    G2    NaN
2   6  74  68  64    G3    NaN
3  36  17  83   4    G2    NaN
4  35  61  20   0    G1    NaN

也不符合预期!

再试试新的方式,

>>> df["sum_a"] = df.groupby("group")["a"].transform(lambda x: sum(x))
>>> df
    a   b   c   d group  sum_a
0  94  32  37  13    G1    129
1  87  95  24  77    G2    123
2   6  74  68  64    G3      6
3  36  17  83   4    G2    123
4  35  61  20   0    G1    129

用transform可以到达预期的结果。

  • 如果需要取两列的数据聚合,写入新的一列要如何操作?transform每次只能取一列的数据操作,所有没法做到。用apply,可以在分组内跨行、跨列操作。
>>> df["sum_ab"] = df.groupby("group").apply(lambda x:(x["a"] +x["b"])).shift()
...
TypeError: incompatible index of inserted column with frame index

incompatible index of inserted column with frame index

报错,说索引不兼容。再看看右侧的输出是什么,

>>> df.groupby("group").apply(lambda x:(x["a"] +x["b"])).shift()
group
G1     0      NaN
       4    126.0
G2     1     96.0
       3    182.0
G3     2     53.0
dtype: float64

>>> type(df.groupby("group").apply(lambda x:(x["a"] +x["b"])).shift())
<class 'pandas.core.series.Series'>

右侧输出的是Series,它的索引有两级,一级是分组名,一级是df一致的索引。所有要重置右侧输出的索引和df一致。

>>> df["sum_ab"] = df.groupby("group").apply(lambda x:(x["a"] +x["b"])).shift().reset_index(le
... vel=0, drop=True)
>>> df
    a   b   c   d group  sum_a  sum_ab
0  94  32  37  13    G1    129     NaN
1  87  95  24  77    G2    123    96.0
2   6  74  68  64    G3      6    53.0
3  36  17  83   4    G2    123   182.0
4  35  61  20   0    G1    129   126.0
  • 另外,也可以自己定义处理函数,
>>> def sum_ab(d):
...     d["sum_abb"] = (d["a"] + d["b"]).shift()
...     return d

>>> df = df.groupby("group").apply(sum_ab)
>>> df
    a   b   c   d group  sum_a  sum_ab  sum_abb
0  94  32  37  13    G1    129     NaN      NaN
1  87  95  24  77    G2    123    96.0      NaN
2   6  74  68  64    G3      6    53.0      NaN
3  36  17  83   4    G2    123   182.0    182.0

  • squeeze参数的作用,先看官方文档说明

squeeze : bool, default False
Reduce the dimensionality of the return type if possible, otherwise return a consistent type.

通过代码看作用

>>> df["group_1"] = "g1"
>>> df
    a   b   c   d group  sum_a  sum_ab  sum_abb group_1
0  94  32  37  13    G1    129     NaN      NaN      g1
1  87  95  24  77    G2    123    96.0      NaN      g1
2   6  74  68  64    G3      6    53.0      NaN      g1
3  36  17  83   4    G2    123   182.0    182.0      g1
4  35  61  20   0    G1    129   126.0    126.0      g1

>>> df.groupby("group_1").apply(lambda x: x["a"].shift())
a         0     1     2    3     4
group_1
g1      NaN  94.0  87.0  6.0  36.0

>>> df.groupby("group").apply(lambda x: x["a"].shift())
group
G1     0     NaN
       4    94.0
G2     1     NaN
       3    87.0
G3     2     NaN
Name: a, dtype: float64

>>> df.groupby("group_1", squeeze=True).apply(lambda x: x["a"].shift())
0     NaN
1    94.0
2    87.0
3     6.0
4    36.0
Name: g1, dtype: float64

>>> df.groupby("group", squeeze=True).apply(lambda x: x["a"].shift())
group
G1     0     NaN
       4    94.0
G2     1     NaN
       3    87.0
G3     2     NaN
Name: a, dtype: float64

>>> type(df.groupby("group").apply(lambda x: x["a"].shift()))
<class 'pandas.core.series.Series'>

>>> type(df.groupby("group_1").apply(lambda x: x["a"].shift()))
<class 'pandas.core.frame.DataFrame'>

>>> type(df.groupby("group", squeeze=True).apply(lambda x: x["a"].shift()))
<class 'pandas.core.series.Series'>

>>> type(df.groupby("group_1", squeeze=True).apply(lambda x: x["a"].shift()))
<class 'pandas.core.series.Series'>

只有1个分组时候,squeeze是False或True的输出结果不一致!squeeze从pandas的1.1.0版本开始将不支持,可以用DataFrame.squeeze()替代

结论

在处理groupby的分组数据时候,如果处理单列的数据,可以用transform,保持和原
DataFrame一致;如果要处理跨列跨行数据时,用apply(和reset_index,如果需要)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值