10 groupby快速上手

本文的目的在于指导读者快速上手groupby。在每个知识点下,我会先说明用法,再给出示例。本文只给出了基本的用法,想要获得更详尽的内容请参阅文档:
Group by: split-apply-combine

10.1 分组

分组依据可以是:

  • 函数,会在各个索引值上被调用一次,其返回值就会被用作分组名称
  • numpy array
  • 字典或Series
  • 列名
  • 以上类型的混合组成的列表

示例

In [1]: df = pd.DataFrame(
   ...:     [
   ...:         ("bird", "Falconiformes", 389.0),
   ...:         ("bird", "Psittaciformes", 24.0),
   ...:         ("mammal", "Carnivora", 80.2),
   ...:         ("mammal", "Primates", np.nan),
   ...:         ("mammal", "Carnivora", 58),
   ...:     ],
   ...:     index=["falcon", "parrot", "lion", "monkey", "leopard"],
   ...:     columns=("class", "order", "max_speed"),
   ...: )
   ...: 

In [2]: df
Out[2]: 
          class           order  max_speed
falcon     bird   Falconiformes      389.0
parrot     bird  Psittaciformes       24.0
lion     mammal       Carnivora       80.2
monkey   mammal        Primates        NaN
leopard  mammal       Carnivora       58.0

# default is axis=0
In [3]: grouped = df.groupby("class")

In [4]: grouped = df.groupby("order", axis="columns")

In [5]: grouped = df.groupby(["class", "order"])

10.2 查看分组

  • grouped.first()注意并不是查看第一个分组,而是查看每个分组的第一个元素
  • grouped.last(),同理
  • grouped.nth(2),同理,查看每个分组的第二个元素
  • grouped.get_group("A"),查看指定分组
  • dict(list(grouped)),把分组转化为字典,可以方便查看。

示例

In [29]: df3 = pd.DataFrame({"X": ["A", "B", "A", "B","A","B"], "Y": [1, 4, 3, 2,4,120]})

In [30]: grouped=df3.groupby('X')

In [31]: grouped.last()
Out[31]: 
     Y
X     
A    4
B  120

In [32]: df3
Out[32]: 
   X    Y
0  A    1
1  B    4
2  A    3
3  B    2
4  A    4
5  B  120

In [33]: grouped.get_group("A")
Out[33]: 
   Y
0  1
2  3
4  4

In [34]: d=dict(list(grouped))

In [35]: d
Out[35]: 
{'A':    X  Y
 0  A  1
 2  A  3
 4  A  4,
 'B':    X    Y
 1  B    4
 3  B    2
 5  B  120}
In [37]: d["A"]
Out[37]: 
   X  Y
0  A  1
2  A  3
4  A  4 

10.3 聚合Aggregation 1

聚合:计算统计量,把组内数据聚合成一个标量,比如计算组内均值。
形如grouped.agg(func)

示例


In [62]: grouped = df.groupby('A')

In [63]: for name, group in grouped:
   ....:     print(name)
   ....:     print(group)
   ....: 
bar
     A      B         C         D
1  bar    one  0.254161  1.511763
3  bar  three  0.215897 -0.990582
5  bar    two -0.077118  1.211526
foo
     A      B         C         D
0  foo    one -0.575247  1.346061
2  foo    two -1.143704  1.627081
4  foo    two  1.193555 -0.441652
6  foo    one -0.408530  0.268520
7  foo  three -0.862495  0.024580

In [68]: grouped.aggregate(np.sum)
Out[68]: 
            C         D
A                      
bar  0.392940  1.732707
foo -1.796421  2.824590

对于一些常用的统计函数,groupby对象可以直接使用,形如grouped.sum()
常用的聚合函数

函数说明
mean()
sum()
size()返回组内数据个数
count()返回每个位置数据的个数,具体的看上边的演示
std()
var()
sem()标准误,即样本均数的标准差,是描述均数抽样分布的离散程度及衡量均数抽样误差大小的尺度,反映的是样本均数之间的变异。标准误不是标准差,是多个样本平均数的标准差。标准误用来衡量抽样误差。标准误越小,表明样本统计量与总体参数的值越接近,样本对总体越有代表性,用样本统计量推断总体参数的可靠度越大。因此,标准误是统计推断可靠性的指标。
describe()
first()取每个分组的第一条数据
last()
nth()取每个分组的第n条数据,如果n是列表则返回一个子集
min()
max()
nunique()返回每个位置unique元素的个数

更详尽的见10.6节

10.4 转换Transformation

转换:输入的形状和输出的形状一致。比如标准化组内数据。
转换会返回一个和分组大小相同的对象。不要在分组对象上原地操作,因为改变分组对象可能会产生意外的效果。
示例

In [42]: index = pd.date_range("10/1/1999", periods=10)
In [44]: ts = pd.Series(np.random.normal(0.5, 2, 10), index)
In [46]: ts
Out[46]: 
1999-10-01    3.557378
1999-10-02   -0.483196
1999-10-03    3.285124
1999-10-04   -0.745478
1999-10-05   -2.002660
1999-10-06    3.390502
1999-10-07    0.946926
1999-10-08    2.007789
1999-10-09    1.848048
1999-10-10   -0.793525
Freq: D, dtype: float64

In [47]: transformed = ts.groupby(lambda x: x.year).transform(
    ...:   .....:     lambda x: (x - x.mean()) / x.std()
    ...:   .....: )
    ...:   .....:

In [48]: transformed
Out[48]: 
1999-10-01    1.218182
1999-10-02   -0.785718
1999-10-03    1.083159
1999-10-04   -0.915795
1999-10-05   -1.539288
1999-10-06    1.135421
1999-10-07   -0.076457
1999-10-08    0.449672
1999-10-09    0.370449
1999-10-10   -0.939624
Freq: D, dtype: float64

如果转换函数输出标量,会自动广播到整个输入数组。


In [49]: max = ts.groupby(lambda x: x.year).transform("max")

In [50]: max
Out[50]: 
1999-10-01    3.557378
1999-10-02    3.557378
1999-10-03    3.557378
1999-10-04    3.557378
1999-10-05    3.557378
1999-10-06    3.557378
1999-10-07    3.557378
1999-10-08    3.557378
1999-10-09    3.557378
1999-10-10    3.557378
Freq: D, dtype: float64

In [51]: ts.groupby(lambda x: x.year).transform(lambda x: x.max() - x.min())
Out[51]: 
1999-10-01    5.560038
1999-10-02    5.560038
1999-10-03    5.560038
1999-10-04    5.560038
1999-10-05    5.560038
1999-10-06    5.560038
1999-10-07    5.560038
1999-10-08    5.560038
1999-10-09    5.560038
1999-10-10    5.560038
Freq: D, dtype: float64            

还有一个常用用法是填补na

In [121]: transformed = grouped.transform(lambda x: x.fillna(x.mean()))

10.5 过滤Filtration

过滤:根据计算结果丢弃一些组,比如根据组内均值过滤掉一些组。而不是丢弃组内的一些值。
filter 函数返回原始对象的子集。filter函数的参数必须是应用在每个分组,返回TrueFalse的函数。
示例

In [136]: sf = pd.Series([1, 1, 2, 3, 3, 3])

In [137]: sf.groupby(sf).filter(lambda x: x.sum() > 2)
Out[137]: 
3    3
4    3
5    3
dtype: int64

In [138]: dff = pd.DataFrame({"A": np.arange(8), "B": list("aabbbbcc")})

In [139]: dff.groupby("B").filter(lambda x: len(x) > 2)
Out[139]: 
   A  B
2  2  b
3  3  b
4  4  b
5  5  b

10.6 聚合Aggregation 2

10.6.1 一次应用多个函数

你可以对groupby对象一次应用多个函数。
示例
注意区别groupby对象分别是SeriesDataframe

In [81]: grouped = df.groupby("A")

In [82]: grouped["C"].agg([np.sum, np.mean, np.std])
Out[82]: 
          sum      mean       std
A                                
bar  0.392940  0.130980  0.181231
foo -1.796421 -0.359284  0.912265

In [83]: grouped.agg([np.sum, np.mean, np.std])
Out[83]: 
            C                             D                    
          sum      mean       std       sum      mean       std
A                                                              
bar  0.392940  0.130980  0.181231  1.732707  0.577569  1.366330
foo -1.796421 -0.359284  0.912265  2.824590  0.564918  0.884785

可以更改聚合后的列名

In [85]: (
   ....:     grouped.agg([np.sum, np.mean, np.std]).rename(
   ....:         columns={"sum": "foo", "mean": "bar", "std": "baz"}
   ....:     )
   ....: )
   ....: 
Out[85]: 
            C                             D                    
          foo       bar       baz       foo       bar       baz
A                                                              
bar  0.392940  0.130980  0.181231  1.732707  0.577569  1.366330
foo -1.796421 -0.359284  0.912265  2.824590  0.564918  0.884785

10.6.2 具名聚合Named aggregation

可以对具体的列使用不同的函数:

In [88]: animals = pd.DataFrame(
   ....:     {
   ....:         "kind": ["cat", "dog", "cat", "dog"],
   ....:         "height": [9.1, 6.0, 9.5, 34.0],
   ....:         "weight": [7.9, 7.5, 9.9, 198.0],
   ....:     }
   ....: )
   ....: 

In [89]: animals
Out[89]: 
  kind  height  weight
0  cat     9.1     7.9
1  dog     6.0     7.5
2  cat     9.5     9.9
3  dog    34.0   198.0

In [90]: animals.groupby("kind").agg(
   ....:     min_height=pd.NamedAgg(column="height", aggfunc="min"),
   ....:     max_height=pd.NamedAgg(column="height", aggfunc="max"),
   ....:     average_weight=pd.NamedAgg(column="weight", aggfunc=np.mean),
   ....: )
   ....: 
Out[90]: 
      min_height  max_height  average_weight
kind                                        
cat          9.1         9.5            8.90
dog          6.0        34.0          102.75

10.6.3 对不同列使用不同聚合函数

In [95]: grouped.agg({"C": "sum", "D": "std"})
Out[95]: 
            C         D
A                      
bar  0.392940  1.366330
foo -1.796421  0.884785

参考:
Group by: split-apply-combine

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值