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. WebForm发布提示:无法加载或找不到oracle.dataaccess文件

    出错提示: 在32位错做系统的开发机上引用了第三方插件(oracle的dataaccess)完成的项目,将发布的程序拷贝到64位的服务器上进行发布时提示无法加载或找不到dataaccess文件. 错误 ...

  2. CSS——图片替换方法比较

    图片替换主要是指将文字替换成图片的技术,即在html语句中使用文字,浏览器显示时用对应的图片显示.其意义在于便于做网站优化(SEO),文字才是搜索引擎寻找的主要对象. 经典的替换方法: Fahrner ...

  3. phpcms v9附件上传后显示链接名称如何改为附件名称?

    使用phpcms v9的朋友都知道,v9在后台添加内容的时候上传附件显示的是一个链接,这样太不人性化了,那怎么显示文件名称呢 ?小编以前发布文章的时候都是上传后复制链接在给文字加上超链接的,这样非常的 ...

  4. commons-logging \ log4j \ slf4j 之间的关系

    最近的一个web项目中要使用到日志,但是对常用的日志记录工具(框架)着实不是很理解,在此mark一下. 1.commons-logging.jar common-logging是apache提供的一个 ...

  5. SSH有端口映射功能(访问本地端口=访问远程端口)

    大部分SSH连接软件都有SSH通道转发功能,就是用这个实现的. 如果Delphi在代码上实现的话,用libSSH 或者 SecureBridge都可以. 代码基本不用帖,思路给大家讲一下吧. SSH有 ...

  6. AseoZdpAseo.init(this, AseoZdpAseo.INSERT_TYPE);

    让以后的人知道吧,这就是一个广告包,相当于广告插件.

  7. IT第十一天、第十二天、第十三天 - 数组的应用、飞行棋游戏的编写和总结

    NIIT第十一天 上午 多维数组 1.数组是引用数据类型 排序 1.冒泡排序法 2.类冒泡排序法 下午 飞行棋游戏 1.项目策划 2.项目规则确认 3.项目模块确认 晚上 1.飞行棋游戏,项目框架的编 ...

  8. BZOJ 1651: [Usaco2006 Feb]Stall Reservations 专用牛棚

    题目 1651: [Usaco2006 Feb]Stall Reservations 专用牛棚 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 553   ...

  9. Spring基于 Annotation 的简单介绍

    tyle="margin:20px 0px 0px; font-size:14px; line-height:26px; font-family:Arial"> 1.使用 @ ...

  10. if语句求三个数中最大的

    Console.WriteLine("请输入第一个数:"); int a = Convert.ToInt32( Console.ReadLine()); Console.Write ...