Pandas进阶之数据聚合


概述

在之前的前面几篇博客中,详细介绍了Pandas的一些基础和高级特性。今天博主继续介绍一个Pandas的进阶之数据聚合。

数据聚合

pandas可以支持像sql语句那样,对数据进行聚合操作。比如:groupby,combine等等。

GroupBy技术

我们可以将一个Pandas的DataFrame结构进行拆分-应用-合并操作。比如:

In [6]: df = DataFrame({'key1':'aabba','key2':["one","two","one","two
   ...: ","one"],"data1":np.random.randn(5),'data2':np.random.randn(5
   ...: )})
In [7]: df
Out[7]:
       data1     data2 key1 key2
0 -0.228886  0.167925    a  one
1 -1.556655  0.640775    a  two
2 -0.508787 -0.578234    b  one
3 -0.279801  0.089786    b  two
4 -0.823011  1.359131    a  one

然后我们可以根据按照key1或者key2在某一列上进行分组,比如:

In [13]: df.groupby('key1')
Out[13]: <pandas.core.groupby.DataFrameGroupBy object at 0x1065c2510>
In [14]: df.groupby('key1').mean()
Out[14]:
         data1     data2
key1
a    -0.869517  0.722611
b    -0.394294 -0.244224
In [18]: df.groupby(['key1','key2']).mean()
Out[18]:
              data1     data2
key1 key2
a    one  -0.525948  0.763528
     two  -1.556655  0.640775
b    one  -0.508787 -0.578234
     two  -0.279801  0.089786
In [19]: df.groupby(['key1','key2']).size()
Out[19]:
key1  key2
a     one     2
      two     1
b     one     1
      two     1
dtype: int64
In [27]: df.groupby('key1')['data1'].mean()
Out[27]:
key1
a   -0.869517
b   -0.394294
Name: data1, dtype: float64

GroupBy对象实际上并没有进行任何计算,只是保留了一份中间数据而已,当执行mean()才会进行将数据分组聚合应用。 如果我们已经对数据进行了分组,然后想对分组的数据进行可定制化的操作那么如何迭代?

In [21]: for name,group in df.groupby('key1'):
    ...:     print name
    ...:     print group
    ...:
a
      data1     data2 key1 key2
0 -0.228886  0.167925    a  one
1 -1.556655  0.640775    a  two
4 -0.823011  1.359131    a  one
b
      data1     data2 key1 key2
2 -0.508787 -0.578234    b  one
3 -0.279801  0.089786    b  two
In [22]: for (name1,name2),group in df.groupby(['key1','key2']):
    ...:     print (name1,name2)
    ...:     print group
    ...:
    ...:
('a', 'one')
      data1     data2 key1 key2
0 -0.228886  0.167925    a  one
4 -0.823011  1.359131    a  one
('a', 'two')
      data1     data2 key1 key2
1 -1.556655  0.640775    a  two
('b', 'one')
      data1     data2 key1 key2
2 -0.508787 -0.578234    b  one
('b', 'two')
      data1     data2 key1 key2
3 -0.279801  0.089786    b  two

groupby默认是在axis=0(行)分组,也可以在列上分组。我们可以通过传入已分组数据进行进行分组,比如:

In [29]: df = DataFrame(np.random.rand(5,5),columns=list('abcde'),index=['Jo','St','We','Ji','Tr'])

In [30]: df
Out[30]:
           a         b         c         d         e
Jo  0.223651  0.374765  0.039368  0.742583  0.083534
St  0.389264  0.938515  0.495707  0.785569  0.605133
We  0.536896  0.326160  0.557036  0.262893  0.367037
Ji  0.590111  0.801715  0.111961  0.046658  0.474800
Tr  0.365418  0.885797  0.397164  0.642887  0.760261
In [37]: df.loc[2:3,['b','c']]=np.nan

In [38]: df
Out[38]:
           a         b         c         d         e
Jo  0.223651  0.374765  0.039368  0.742583  0.083534
St  0.389264  0.938515  0.495707  0.785569  0.605133
We  0.536896       NaN       NaN  0.262893  0.367037
Ji  0.590111  0.801715  0.111961  0.046658  0.474800
Tr  0.365418  0.885797  0.397164  0.642887  0.760261
In [51]: mapping={'a':'red','b':'red','c':'blue','d':'blue','e':'red','f':'orange'}

In [52]: by = df.groupby(mapping,axis=1)

In [53]: by
Out[53]: <pandas.core.groupby.DataFrameGroupBy object at 0x106876850>

In [54]: by.sum()
Out[54]:
        blue       red
Jo  0.781950  0.681950
St  1.281276  1.932913
We  0.262893  0.903934
Ji  0.158619  1.866626
Tr  1.040051  2.011476
In [55]: by.count()
Out[55]:
    blue  red
Jo     2    3
St     2    3
We     1    2
Ji     2    3
Tr     2    3

groupby还可以通过函数和索引级别来分组,比如:

In [59]: df.groupby(len).sum()
Out[59]:
         a         b       c         d         e
2  2.10534  3.000792  1.0442  2.480589  2.290765
In [73]: df.groupby([len,key_list]).min()
Out[73]:
              a         b         c         d         e
2 one  0.223651  0.374765  0.039368  0.262893  0.083534
  two  0.365418  0.801715  0.111961  0.046658  0.474800

常用聚合函数

  • count 分组中的数量
  • sum 分组中的和
  • mean 分组中的平均值
  • median 算数中位数
  • std,var标准差和方差
  • max,min 最大值和最小值
  • prod 值得积
  • frist,last 第一个和最后一个值

上述都可以通过聚合之后的对对象操作。

In [82]: df
Out[82]:
      data1     data2 key1 key2
0  2.346840  1.574532    a  one
1 -0.225204 -0.555727    a  two
2  0.129150 -0.219370    b  one
3 -0.856133 -1.382830    b  two
4 -0.300663 -2.461491    a  one

In [83]: grouped = df.groupby('key1')

In [84]: def custom(arr):
    ...:     return arr.max()-arr.min()
    ...:

In [85]: grouped.agg(custom)
Out[85]:
         data1     data2
key1
a     2.647503  4.036022
b     0.985283  1.163460
In [90]: grouped.agg('mean')
Out[90]:
         data1     data2
key1
a     0.606991 -0.480895
b    -0.363492 -0.801100
In [91]: grouped.agg(['std','mean',custom])
Out[91]:
         data1                         data2
           std      mean    custom       std      mean    custom
key1
a     1.507226  0.606991  2.647503  2.019051 -0.480895  4.036022
b     0.696700 -0.363492  0.985283  0.822690 -0.801100  1.163460
#如果传入的是由元组构成的列表
In [93]: grouped.agg([('s','std'),('m','mean'),('c',custom)])
Out[93]:
         data1                         data2
             s         m         c         s         m         c
key1
a     1.507226  0.606991  2.647503  2.019051 -0.480895  4.036022
b     0.696700 -0.363492  0.985283  0.822690 -0.801100  1.163460

分组级别的运算可以通过transform进行广播运算,比如:

In [104]: df
Out[104]:
           a         b         c         d         e
Jo  0.416052  0.627895  0.862025  0.059178  0.679535
St  0.411298  0.364009  0.977781  0.028793  0.513383
We  0.067403  0.843924  0.419891  0.603240  0.787490
Ji  0.268642  0.722305  0.235712  0.647945  0.399922
Tr  0.413175  0.099380  0.966640  0.700351  0.321278
In [102]: def custom(arr):
     ...:     return arr-arr.mean()
     ...:

In [103]: df.groupby(['one','two','one','two','one']).transform(custom)
Out[103]:
           a         b         c         d         e
Jo  0.117176  0.104162  0.112506 -0.395078  0.083434
St  0.071328 -0.179148  0.371034 -0.309576  0.056731
We -0.231474  0.320191 -0.329628  0.148984  0.191389
Ji -0.071328  0.179148 -0.371034  0.309576 -0.056731
Tr  0.114298 -0.424353  0.217121  0.246094 -0.274823

transform会将一个函数应用到各个分组,然后将结果放置到适当的位置上。但是它只能产生两种结果:要么产生一个可以广播的标量(np.mean),要么产生一个相同大小的结果数组。

apply 拆分-应用-合并

In [119]: def top(df,n=5,column='tip_pct'):
     ...:     return df.sort_values(by=column,axis='index')[-n:]

In [120]: top(tips,n=6)
Out[120]:
     total_bill   tip     sex smoker  day    time  size   tip_pct
109       14.31  4.00  Female    Yes  Sat  Dinner     2  0.279525
183       23.17  6.50    Male    Yes  Sun  Dinner     4  0.280535
232       11.61  3.39    Male     No  Sat  Dinner     2  0.291990
67         3.07  1.00  Female    Yes  Sat  Dinner     1  0.325733
178        9.60  4.00  Female    Yes  Sun  Dinner     2  0.416667
172        7.25  5.15    Male    Yes  Sun  Dinner     2  0.710345

参考书籍

1.《Python 数据分析》 2.《Python数据挖掘与分析》 3.《利用Python进行数据分析》

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏编程

享学课堂谈python中else的用途

今天我能聊聊python中的else,大家都知道 Python 中else的基本用法是在条件控制语句中的 if...elif...else...,但是else ...

1936
来自专栏程序员叨叨叨

6.7 操作符优先顺序

Cg语言中操作符的优先顺序如表 3所示,从上到下表示从高级到低级的优先级;同一行的操作符具有同等优先级。该表参考了Cg教程_可编程实时图形权 威指南第3.3.1...

1042
来自专栏不是你的bug

计算机是如何实现加法的

我们除去右下角看其他部分,和或运算结果是完全一致的。再单独看一下右下角,输入都为1时输出为0这不就是与非的操作结果吗。那我们将输入同时给到或门和与非门看下他们的...

2981
来自专栏Java面试通关手册

精研3道简单的网易2018校招编程题

下面三道编程题来自网易2018校招编程题,这三道应该来说是非常简单的编程题了,这些题目大家稍微有点编程和数学基础的话应该没什么问题。看答案之前一定要自己先想一下...

2016
来自专栏Android知识点总结

再见kotlin----01语句控制

812
来自专栏大数据杂谈

从 Zero 到 Hero ,一文掌握 Python

2059
来自专栏一个会写诗的程序员的博客

第6章 类型系统

6.3 基本类型(Primitive Types) 6.3.1 Number: 包含整型与浮点型等 6.3.2 Char: 字符类型(Character) ...

1083
来自专栏hbbliyong

看到他我一下子就悟了-- 泛型(2)

   先说些题外话,只所以写这些东西。是看了CSDN上的曹版主的一篇:手把手教编程,不知道有没有人愿意参与。说实话,我工作四年,总感觉晕晕乎乎的,好多技术都 懂...

2979
来自专栏blackheart的专栏

[程序设计语言]-[核心概念]-03:控制流

0.概述 前面介绍了语言的演进以及一些基础概念后,从本篇开始进入了语言的核心问题中。这一篇讨论的是语言计算模型(大致可以用控制流来表述),大致如下7种: 顺序执...

21110
来自专栏DT乱“码”

MYSQL Count(*)和Count(1)区别

在SQL Server中Count(*)或者Count(1)或者Count([列])或许是最常用的聚合函数。很多人其实对这三者之间是区分不清的。本文会...

2088

扫码关注云+社区

领取腾讯云代金券