zoukankan      html  css  js  c++  java
  • Python 数据分析(二 本实验将学习利用 Python 数据聚合与分组运算,时间序列,金融与经济数据应用等相关知识

    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 分组技术的本质。

  • 相关阅读:
    ecshop简单结构
    关于dwt文件和lbi文件
    ecshop各个文件夹作用
    修改ecshop模板体会
    PHP的字符串函数
    数组的相关处理函数
    PHP连接数据库
    Headless谷歌selenium使用
    关于无界面浏览器、request模块、tesseract模块的部分笔记
    爬取某城市公交钱路--xpath过滤
  • 原文地址:https://www.cnblogs.com/timssd/p/5429176.html
Copyright © 2011-2022 走看看