Python 数据分析(二)

本实验将学习利用 Python 数据聚合与分组运算,时间序列,金融与经济数据应用等相关知识

第1节
groupby 技术
第2节
数据聚合
第3节
分组级运算和转换
第4节
透视表和交叉表
第5节
时间序列
第6节
日期的规范、频率以及移动
第7节
时区处理
第8节
时期及算术运算
第9节
重采样及频率转换
第10节
时间序列绘图

groupby 技术


一、实验简介

  Python 数据分析(二)需要同学们先行学完 Python 数据分析(一)的课程。

  对数据集进行分组并对各组应用一个函数(无论是聚合还是转换),这是数据分析工作中的重要环节。在数据集准备好之后,通常的任务就是计算分组统 计或生成透视表。pandas 提供了一个灵活高效的 groupby 功能,它使我们能以一种自然的方式对数据集进行切片、切块、摘要等操作。

  分组运算的第一阶段,pandas 对象(无论是 Series、DataFrame 还是其他的)中的数据会根据你所提供的一个或多个键被拆分(split)为多组。拆分操作是在对象的特定轴上执行的。例如,DataFrame 可以在其行(axis=0)或列(axis=1)上进行分组。然后,将一个函数应用到各个分组并产生一个新值。最后,所有这些函数的执行结果会被合并到最 终的结果对象中。结果对象的形式一般取决于数据上所执行的操作。

  分组键可以有多种形式,且类型不必相同:

  • 列表或数组,其长度与待分组的轴一样
  • 表示 DataFrame 某个列名的值
  • 字典或 Series,给出待分组轴上的值与分组名之间的对应关系
  • 函数、用于处理轴索引中的各个标签

  注意,后三种都只是快捷方式而已,其最终目的仍然是产生一组用于拆分对象的值。

In [5]: df = DataFrame({'key1':['a','a','b','b','a'],
                'key2':['one','two','one','two','one'],
                'data1':np.random.randn(5),
                'data2':np.random.randn(5)})

In [6]: df
Out[6]:
      data1     data2 key1 key2
0 -1.884515  0.735152    a  one
1  0.320270  1.364803    a  two
2  1.190752 -0.877677    b  one
3 -2.714275 -0.641703    b  two
4  0.586653 -0.451896    a  one

  在上面的例子中,假设我们想要按 key1 进行分组,并计算 data1 列的平均值。实现该功能的方式有很多,而我们这里要用的是:访问 data1,并根据 key1调用 groupby:

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

In [8]: grouped
Out[8]: <pandas.core.groupby.SeriesGroupBy object at 0x112d53290>

  变量 grouped 是一个 GroupBy 对象。它实际上还没有进行任何计算,只是含有一些有关分组键 df['key1']的中间数据而已。换句话说,该对象已经有了接下来对各分组执行运算所需的一切信息。例如,我们可以调用 GroupBy 的 mean 方法来计算分组平均值:

In [10]: grouped.mean()
Out[10]:
key1
a   -0.325864
b   -0.761762
Name: data1, dtype: float64

  数据(Series)根据分组键进行了聚合,产生了一个新的 Series,其索引为 key1列中的唯一值。如果我们传入多个数组,就会得到不同的结果:

In [11]: means = df['data1'].groupby([df['key1'],df['key2']]).mean()

In [12]: means
Out[12]:
key1  key2
a     one    -0.648931
      two     0.320270
b     one     1.190752
      two    -2.714275
Name: data1, dtype: float64

  这里,我们通过两个键对数据进行了分组,得到的 Series 具有一个层次化索引(由唯一的键对组成):

In [13]: means.unstack()
Out[13]:
key2       one       two
key1
a    -0.648931  0.320270
b     1.190752 -2.714275

  在上面这些示例中,分组键均为 Series。实际上,分组键可以是任何长度适当的数组:

In [14]: states = np.array(['Ohio','California','California','Ohio','Ohio'])

In [15]: years = np.array([2005, 2005, 2006, 2005, 2006])

In [16]: df['data1'].groupby([states,years]).mean()
Out[16]:
California  2005    0.320270
            2006    1.190752
Ohio        2005   -2.299395
            2006    0.586653
Name: data1, dtype: float64

In [17]: # 此外,还可以将列名用作分组键

In [18]: df.groupby('key1').mean()
Out[18]:
         data1     data2
key1
a    -0.325864  0.549353
b    -0.761762 -0.759690

In [19]: df.groupby(['key1','key2']).mean()
Out[19]:
              data1     data2
key1 key2
a    one  -0.648931  0.141628
     two   0.320270  1.364803
b    one   1.190752 -0.877677
     two  -2.714275 -0.641703

  在执行 df.groupby('key1').mean()时,结果中没有 key2 列。这是因为 df['key2']不是数值数据,所以从结果中排除了。默认情况下,所有数值列都会被聚合,虽然有时可能会被过滤为一个子集(稍后会讲到)。

  GroupBy 的 size 方法可以返回一个含有分组大小的 Series:

In [20]: df.groupby(['key1','key2']).size()
Out[20]:
key1  key2
a     one     2
      two     1
b     one     1
      two     1
dtype: int64

 

二、对分组进行迭代

   GroupBy 对象支持迭代,可以产生一组二元元组(由分组名和数据块组成)

In [21]: for name,group in df.groupby('key1'):
   ....:     print name
   ....:     print group
   ....:
a
      data1     data2 key1 key2
0 -1.884515  0.735152    a  one
1  0.320270  1.364803    a  two
4  0.586653 -0.451896    a  one
b
      data1     data2 key1 key2
2  1.190752 -0.877677    b  one
3 -2.714275 -0.641703    b  two

In [22]: # 对于多重键的情况,元组的第一个元素将会是由键值组成的元组

In [23]: for (k1, k2),group in df.groupby(['key1','key2']):
   ....:     print k1, k2
   ....:     print group
   ....:
a one
      data1     data2 key1 key2
0 -1.884515  0.735152    a  one
4  0.586653 -0.451896    a  one
a two
     data1     data2 key1 key2
1  0.32027  1.364803    a  two
b one
      data1     data2 key1 key2
2  1.190752 -0.877677    b  one
b two
      data1     data2 key1 key2
3 -2.714275 -0.641703    b  two

  当然,我们可以对这些数据片段做任何操作。有一个你可能会觉得有用的运算:将这些数据片段做成一个字典。

In [25]: pieces = dict(list(df.groupby('key1')))

In [26]: pieces['b']
Out[26]:
      data1     data2 key1 key2
2  1.190752 -0.877677    b  one
3 -2.714275 -0.641703    b  two

  groupby 默认是在 axis=0 上进行分组的,通过设置也可以在其他任何轴上进行分组。拿上面例子中的 df 来说,我们可以根据 dtype 对列进行分组:

In [27]: df.dtypes
Out[27]:
data1    float64
data2    float64
key1      object
key2      object
dtype: object

In [28]: grouped = df.groupby(df.dtypes, axis =1)

In [29]: dict(list(grouped))
Out[29]:
{dtype('float64'):       data1     data2
 0 -1.884515  0.735152
 1  0.320270  1.364803
 2  1.190752 -0.877677
 3 -2.714275 -0.641703
 4  0.586653 -0.451896, dtype('O'):   key1 key2
 0    a  one
 1    a  two
 2    b  one
 3    b  two
 4    a  one}

  

三、选取一个或一组列

  对于由 DataFrame 产生的 GroupBy 对象,如果用一个(单个字符串)或一组(字符串数组)列名对其进行索引,就能实现选取部分列进行聚合的目的,也就是说:


df.groupby('key1')['data1']
df.groupby('key1')[['data2']]

  是以下代码的语法糖:

df['data1'].groupby(df['key1'])
df[['data2']].groupby(df['key1'])

  尤其对于大量数据集,很有可能只需要对部分列进行聚合。例如,在前面那个数据集中,如果只需计算 data2 列的平均值并以 DataFrame 形式得到结果,我们可以编写:

In [21]: df.groupby(['key1','key2'])[['data2']].mean()
Out[21]:
              data2
key1 key2
a    one  -0.035973
     two  -1.650808
b    one   0.610671
     two   0.407438

  这种索引操作所返回的对象是一个已分组的 DataFrame(如果传入的是列表或数组)或已分组的 Series(如果传入的是标量形式的单个列名):

In [22]: s_groupby = df.groupby(['key1','key2'])['data2']

In [23]: s_groupby.mean()
Out[23]:
key1  key2
a     one    -0.035973
      two    -1.650808
b     one     0.610671
      two     0.407438
Name: data2, dtype: float64

  注意观察行21和22之间的区别,前面返回的是一个 DataFrame,后面返回的是一个 Series

四、通过字典或 Series 进行分组

  除数组以外,分组信息还可以其他形式存在。来看一个示例:

In [4]: people = DataFrame(np.random.randn(5,5),
                   columns = ['a','b','c','d','e'],
                   index = ['Joe','Steve','Wes','Jim','Travis'])

In [5]: people.ix[2:3,['b','c']] = np.nan

In [6]: people
Out[6]:
               a         b         c         d         e
Joe    -0.131332  1.361534  0.885761  1.250524  0.723013
Steve  -0.968665 -0.024584  1.213288  0.564578 -0.666432
Wes     0.108587       NaN       NaN  0.678532 -1.182141
Jim     0.643063  0.065343  0.008009 -1.651852 -1.156628
Travis  0.113156  0.076969  0.353941 -0.096054 -0.351033

In [7]: #假设已知列的分组关系,并希望根据分组计算列的总计

In [8]: mapping = {'a':'red','b':'red','c':'blue',
           'd':'blue','e':'red','f':'orange'}

In [9]: #现在,只需将这个字典传给 groupby 即可

In [10]: by_column = people.groupby(mapping,axis=1)

In [11]: by_column.sum()
Out[11]:
            blue       red
Joe     2.136285  1.953214
Steve   1.777866 -1.659681
Wes     0.678532 -1.073554
Jim    -1.643843 -0.448222
Travis  0.257887 -0.160908

  Series也有同样的功能,它可以被看做一个固定大小的映射。对于上面那个例子,如果用 Series 作为分组键,则 pandas 会检查 Series 以确保其索引跟分组轴是对齐的:

In [13]: map_series = Series(mapping)

In [14]: map_series
Out[14]:
a       red
b       red
c      blue
d      blue
e       red
f    orange
dtype: object

In [15]: people.groupby(map_series,axis=1).count()
Out[15]:
        blue  red
Joe        2    3
Steve      2    3
Wes        1    2
Jim        2    3
Travis     2    3

五、通过函数进行分组

  相较于字典或 Series,Python 函数在定义分组映射关系时可以更有创意且更为抽象。任何被当做分组键的函数都会在各个索引值上被调用一次,其返回值就会被用作分组名称。具体点说,以上一 小节的示例 DataFrame 为例,其索引值为人的名字。假设你希望根据人名的长度进行分组,虽然可以求取一个字符串长度数组,但其实仅仅传入 len 函数就可以了:

In [16]: people.groupby(len).sum()
Out[16]:
          a         b         c         d         e
3  0.620317  1.426876  0.893770  0.277204 -1.615756
5 -0.968665 -0.024584  1.213288  0.564578 -0.666432
6  0.113156  0.076969  0.353941 -0.096054 -0.351033

  将函数跟数组、列表、字典、Series 混合使用也不是问题,因为任何东西最终都会被转换为数组:


In [17]: key_list = ['one','one','one','two','two']

In [18]: people.groupby([len,key_list]).min()
Out[18]:
              a         b         c         d         e
3 one -0.131332  1.361534  0.885761  0.678532 -1.182141
  two  0.643063  0.065343  0.008009 -1.651852 -1.156628
5 one -0.968665 -0.024584  1.213288  0.564578 -0.666432
6 two  0.113156  0.076969  0.353941 -0.096054 -0.351033

  层次化索引数据集最方便的地方就在于它能够根据索引级别进行聚合。要实现该目的,通过 level 关键字传入级别编号或名称即可:

In [22]: columns = pd.MultiIndex.from_arrays([['US','US',
  'US','CN','CN'],[1,3,5,1,3]],names=['cty','tenor'])

In [23]: hier_df = DataFrame(np.random.randn(4,5),
                   columns = columns)

In [24]: hier_df
Out[24]:
cty          US                            CN
tenor         1         3         5         1         3
0      0.823673  0.783013  0.777291 -0.065750  0.507580
1     -2.173389 -0.339692 -1.793867 -1.075630 -0.235964
2      1.973584  0.526835 -1.274129 -0.355864 -0.917485
3      0.984408  0.246716  0.383760 -2.521464  0.078212

In [25]: hier_df.groupby(level='cty',axis=1).count()
Out[25]:
cty  CN  US
0     2   3
1     2   3
2     2   3
3     2   3

六、作业

  好了同学们,你们将上面的代码操练操练,想明白 groupby 分组技术的本质。

Python 数据分析(二 本实验将学习利用 Python 数据聚合与分组运算,时间序列,金融与经济数据应用等相关知识的更多相关文章

  1. Python数据聚合和分组运算(1)-GroupBy Mechanics

    前言 Python的pandas包提供的数据聚合与分组运算功能很强大,也很灵活.<Python for Data Analysis>这本书第9章详细的介绍了这方面的用法,但是有些细节不常用 ...

  2. 《python for data analysis》第九章,数据聚合与分组运算

    # -*- coding:utf-8 -*-# <python for data analysis>第九章# 数据聚合与分组运算import pandas as pdimport nump ...

  3. Python之数据聚合与分组运算

    Python之数据聚合与分组运算 1. 关系型数据库方便对数据进行连接.过滤.转换和聚合. 2. Hadley Wickham创建了用于表示分组运算术语"split-apply-combin ...

  4. 《利用python进行数据分析》读书笔记--第九章 数据聚合与分组运算(一)

    http://www.cnblogs.com/batteryhp/p/5046450.html 对数据进行分组并对各组应用一个函数,是数据分析的重要环节.数据准备好之后,通常的任务就是计算分组统计或生 ...

  5. 利用python进行数据分析之数据聚合和分组运算

    对数据集进行分组并对各分组应用函数是数据分析中的重要环节. group by技术 pandas对象中的数据会根据你所提供的一个或多个键被拆分为多组,拆分操作是在对象的特定轴上执行的,然后将一个函数应用 ...

  6. 利用Python进行数据分析-Pandas(第六部分-数据聚合与分组运算)

    对数据集进行分组并对各组应用一个函数(无论是聚合还是转换),通常是数据分析工作中的重要环节.在将数据集加载.融合.准备好之后,通常是计算分组统计或生成透视表.pandas提供了一个灵活高效的group ...

  7. 【学习】数据聚合和分组运算【groupby】

    分组键可以有多种方式,且类型不必相同 列表或数组, 某长度与待分组的轴一样 表示DataFrame某个列名的值 字典或Series,给出待分组轴上的值与分组名之间的对应关系 函数用于处理轴索引或索引中 ...

  8. Python 数据分析—第九章 数据聚合与分组运算

    打算从后往前来做笔记 第九章 数据聚合与分组运算 分组 #生成数据,五行四列 df = pd.DataFrame({'key1':['a','a','b','b','a'], 'key2':['one ...

  9. python数据分析之:数据聚合与分组运算

    在数据库中,我们可以对数据进行分类,聚合运算.例如groupby操作.在pandas中同样也有类似的功能.通过这些聚合,分组操作,我们可以很容易的对数据进行转换,清洗,运算.比如如下图,首先通过不同的 ...

随机推荐

  1. 在mysql中创建存储过程出现1307错误,解决方法

    需要删除mysql数据库下proc表 在重新创建 CREATE TABLE `proc` ( `db` char(64) character set utf8 collate utf8_bin NOT ...

  2. mobilize扁平化的fullPage.js类工具使用心得

    可以生成一个fullPage效果的主页,但是列表页面和内容页面呢? 主页中的block,可以选择多种组建生成.甚至连form都有: 应该改造其源代码,动态化和cms系统化,添加二三级页面模板: == ...

  3. C#_会员管理系统:开发八(权限分配)

    数据库设计 这里由于增加了普通用户权限值,我们需要对数据库结构稍作修改.这里在MovieAccount表中增加4列内容 分别用于 RightFManager       判断普通用户管理界面权限   ...

  4. 关于hibernate子查询参数的问题

    private Map<String, Object> createWblHqlContext(boolean needGroup, String startDate, String en ...

  5. 【Linux命令】Ubuntu14.04+QT5.2配置mysql

    安装qt: 官网下载qt5.2.1:qt-opensource-linux-x64-5.2.1.run 直接命令行运行:./qt-opensource-linux-x64-5.2.1.run 选择安装 ...

  6. The Power of Reading——英语学习小技巧之七

    This method is "The Power of Reading" and it comes from an article by Dr.Stephen Krashen. ...

  7. Javabyte[]数组和十六进制String之间的转换Util------包含案例和代码

    Java中byte用二进制表示占用8位,而我们知道16进制的每个字符需要用4位二进制位来表示(23 + 22 + 21 + 20 = 15),所以我们就可以把每个byte转换成两个相应的16进制字符, ...

  8. iOS开发中两个不错的宏定义

    /** Synthsize a weak or strong reference. Example: @weakify(self) [self doSomething^{ @strongify(sel ...

  9. php定时输出

    //PHP定时输出 ob_end_flush(); //关闭输出缓冲 set_time_limit(0); //设置最大执行时间为无限制 echo '============开始=========== ...

  10. access数据库

    //访问动态创建access数据库 string conn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + Server.M ...