Python 数据分析(二)

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

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

groupby 技术


一、实验简介

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

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

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

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

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

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

  1. In [5]: df = DataFrame({'key1':['a','a','b','b','a'],
  2. 'key2':['one','two','one','two','one'],
  3. 'data1':np.random.randn(5),
  4. 'data2':np.random.randn(5)})
  5. In [6]: df
  6. Out[6]:
  7. data1 data2 key1 key2
  8. 0 -1.884515 0.735152 a one
  9. 1 0.320270 1.364803 a two
  10. 2 1.190752 -0.877677 b one
  11. 3 -2.714275 -0.641703 b two
  12. 4 0.586653 -0.451896 a one

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

  1. In [7]: grouped = df['data1'].groupby(df['key1'])
  2. In [8]: grouped
  3. Out[8]: <pandas.core.groupby.SeriesGroupBy object at 0x112d53290>

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

  1. In [10]: grouped.mean()
  2. Out[10]:
  3. key1
  4. a -0.325864
  5. b -0.761762
  6. Name: data1, dtype: float64

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

  1. In [11]: means = df['data1'].groupby([df['key1'],df['key2']]).mean()
  2. In [12]: means
  3. Out[12]:
  4. key1 key2
  5. a one -0.648931
  6. two 0.320270
  7. b one 1.190752
  8. two -2.714275
  9. Name: data1, dtype: float64

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

  1. In [13]: means.unstack()
  2. Out[13]:
  3. key2 one two
  4. key1
  5. a -0.648931 0.320270
  6. b 1.190752 -2.714275

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

  1. In [14]: states = np.array(['Ohio','California','California','Ohio','Ohio'])
  2. In [15]: years = np.array([2005, 2005, 2006, 2005, 2006])
  3. In [16]: df['data1'].groupby([states,years]).mean()
  4. Out[16]:
  5. California 2005 0.320270
  6. 2006 1.190752
  7. Ohio 2005 -2.299395
  8. 2006 0.586653
  9. Name: data1, dtype: float64
  10. In [17]: # 此外,还可以将列名用作分组键
  11. In [18]: df.groupby('key1').mean()
  12. Out[18]:
  13. data1 data2
  14. key1
  15. a -0.325864 0.549353
  16. b -0.761762 -0.759690
  17. In [19]: df.groupby(['key1','key2']).mean()
  18. Out[19]:
  19. data1 data2
  20. key1 key2
  21. a one -0.648931 0.141628
  22. two 0.320270 1.364803
  23. b one 1.190752 -0.877677
  24. two -2.714275 -0.641703

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

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

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

 

二、对分组进行迭代

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

  1. In [21]: for name,group in df.groupby('key1'):
  2. ....: print name
  3. ....: print group
  4. ....:
  5. a
  6. data1 data2 key1 key2
  7. 0 -1.884515 0.735152 a one
  8. 1 0.320270 1.364803 a two
  9. 4 0.586653 -0.451896 a one
  10. b
  11. data1 data2 key1 key2
  12. 2 1.190752 -0.877677 b one
  13. 3 -2.714275 -0.641703 b two
  14. In [22]: # 对于多重键的情况,元组的第一个元素将会是由键值组成的元组
  15. In [23]: for (k1, k2),group in df.groupby(['key1','key2']):
  16. ....: print k1, k2
  17. ....: print group
  18. ....:
  19. a one
  20. data1 data2 key1 key2
  21. 0 -1.884515 0.735152 a one
  22. 4 0.586653 -0.451896 a one
  23. a two
  24. data1 data2 key1 key2
  25. 1 0.32027 1.364803 a two
  26. b one
  27. data1 data2 key1 key2
  28. 2 1.190752 -0.877677 b one
  29. b two
  30. data1 data2 key1 key2
  31. 3 -2.714275 -0.641703 b two

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

  1. In [25]: pieces = dict(list(df.groupby('key1')))
  2. In [26]: pieces['b']
  3. Out[26]:
  4. data1 data2 key1 key2
  5. 2 1.190752 -0.877677 b one
  6. 3 -2.714275 -0.641703 b two

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

  1. In [27]: df.dtypes
  2. Out[27]:
  3. data1 float64
  4. data2 float64
  5. key1 object
  6. key2 object
  7. dtype: object
  8. In [28]: grouped = df.groupby(df.dtypes, axis =1)
  9. In [29]: dict(list(grouped))
  10. Out[29]:
  11. {dtype('float64'): data1 data2
  12. 0 -1.884515 0.735152
  13. 1 0.320270 1.364803
  14. 2 1.190752 -0.877677
  15. 3 -2.714275 -0.641703
  16. 4 0.586653 -0.451896, dtype('O'): key1 key2
  17. 0 a one
  18. 1 a two
  19. 2 b one
  20. 3 b two
  21. 4 a one}

  

三、选取一个或一组列

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

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

  是以下代码的语法糖:

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

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

  1. In [21]: df.groupby(['key1','key2'])[['data2']].mean()
  2. Out[21]:
  3. data2
  4. key1 key2
  5. a one -0.035973
  6. two -1.650808
  7. b one 0.610671
  8. two 0.407438

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

  1. In [22]: s_groupby = df.groupby(['key1','key2'])['data2']
  2. In [23]: s_groupby.mean()
  3. Out[23]:
  4. key1 key2
  5. a one -0.035973
  6. two -1.650808
  7. b one 0.610671
  8. two 0.407438
  9. Name: data2, dtype: float64

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

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

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

  1. In [4]: people = DataFrame(np.random.randn(5,5),
  2. columns = ['a','b','c','d','e'],
  3. index = ['Joe','Steve','Wes','Jim','Travis'])
  4. In [5]: people.ix[2:3,['b','c']] = np.nan
  5. In [6]: people
  6. Out[6]:
  7. a b c d e
  8. Joe -0.131332 1.361534 0.885761 1.250524 0.723013
  9. Steve -0.968665 -0.024584 1.213288 0.564578 -0.666432
  10. Wes 0.108587 NaN NaN 0.678532 -1.182141
  11. Jim 0.643063 0.065343 0.008009 -1.651852 -1.156628
  12. Travis 0.113156 0.076969 0.353941 -0.096054 -0.351033
  13. In [7]: #假设已知列的分组关系,并希望根据分组计算列的总计
  14. In [8]: mapping = {'a':'red','b':'red','c':'blue',
  15. 'd':'blue','e':'red','f':'orange'}
  16. In [9]: #现在,只需将这个字典传给 groupby 即可
  17. In [10]: by_column = people.groupby(mapping,axis=1)
  18. In [11]: by_column.sum()
  19. Out[11]:
  20. blue red
  21. Joe 2.136285 1.953214
  22. Steve 1.777866 -1.659681
  23. Wes 0.678532 -1.073554
  24. Jim -1.643843 -0.448222
  25. Travis 0.257887 -0.160908

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

  1. In [13]: map_series = Series(mapping)
  2. In [14]: map_series
  3. Out[14]:
  4. a red
  5. b red
  6. c blue
  7. d blue
  8. e red
  9. f orange
  10. dtype: object
  11. In [15]: people.groupby(map_series,axis=1).count()
  12. Out[15]:
  13. blue red
  14. Joe 2 3
  15. Steve 2 3
  16. Wes 1 2
  17. Jim 2 3
  18. Travis 2 3

五、通过函数进行分组

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

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

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

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

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

  1. In [22]: columns = pd.MultiIndex.from_arrays([['US','US',
  2. 'US','CN','CN'],[1,3,5,1,3]],names=['cty','tenor'])
  3. In [23]: hier_df = DataFrame(np.random.randn(4,5),
  4. columns = columns)
  5. In [24]: hier_df
  6. Out[24]:
  7. cty US CN
  8. tenor 1 3 5 1 3
  9. 0 0.823673 0.783013 0.777291 -0.065750 0.507580
  10. 1 -2.173389 -0.339692 -1.793867 -1.075630 -0.235964
  11. 2 1.973584 0.526835 -1.274129 -0.355864 -0.917485
  12. 3 0.984408 0.246716 0.383760 -2.521464 0.078212
  13. In [25]: hier_df.groupby(level='cty',axis=1).count()
  14. Out[25]:
  15. cty CN US
  16. 0 2 3
  17. 1 2 3
  18. 2 2 3
  19. 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. 在 Android 中 Intent 的概念及应用

    一.显式Intent: startActivity(new Intent(MainActivity.this, 类名.class));   二.隐式Intent: 1.在AndroidManiFest ...

  2. Group By 多个分组集小结 --GROUPING SETS,GROUP BY CUBE,GROUP BY ROLLUP,GROUPING(),GROUPING_ID()

    T-SQL 多个分组集共有三种 GROUPING SETS, CUBE, 以及ROLLUP, 其中 CUBE和ROLLUP可以当做是GROUPING SETS的简写版 示例数据库下载: http:// ...

  3. python切片练习

    这块儿没什么难的,细心一点就好 L = [] n = 1 while n <= 99: L.append(n) n = n + 2 print(L) #但是在Python中,代码不是越多越好,而 ...

  4. mysql性能调优与架构设计(一)商业需求与系统架构对性能的影响

    这里我们就拿一个看上去很简单的功能来分析一下. 需求:一个论坛帖子总量的统计附加要求:实时更新 在很多人看来,这个功能非常容易实现,不就是执行一条SELECT COUNT(*)的Query 就可以得到 ...

  5. php随笔8-thinkphp OA系统 客户管理

    Action: CustomerinfosAction.class.php <?php /* * 客户信息 控制器 * @author lifu <504861378@qq.com> ...

  6. openstack 入门1

    介绍 Rackspace & NASA软件开源项目的组合安装配置复杂基础设施资源的系统管理平台 (网络,计算,存储)个人打井 vs 自来水厂 组件&原理 Horizon -- UI模块 ...

  7. javascript单元测试(转)

    1.      什么是单元测试 在计算机编程中,单元测试(又称为模块测试)是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作.程序单元是应用的最小可测试部件.在过程化编程中,一个单元就是单 ...

  8. Using WMIC For Gathering System Info

    WMIC is a command line interface to WMI (Windows Management Instrumentation). While it has many uses ...

  9. switf资源

    http://www.swiftv.cn/ http://letsswift.com/

  10. 全局获取Context的技巧

    全局获取Context的技巧 在android开发中,非常多地方都要用到Context上下文这个类对象,比方:弹出 Toast 的时候须要.启动活动的时候须要.发送广播的时候须要.操作数据库的时候须要 ...