zoukankan      html  css  js  c++  java
  • Python数据聚合和分组运算(1)-GroupBy Mechanics

    前言

    Python的pandas包提供的数据聚合与分组运算功能很强大,也很灵活。《Python for Data Analysis》这本书第9章详细的介绍了这方面的用法,但是有些细节不常用就容易忘记,遂打算把书中这部分内容总结在博客里,以便复习查看。根据书中的章节,这部分知识包括以下四部分:

    1.GroupBy Mechanics(groupby技术)

    2.Data Aggregation(数据聚合)

    3.Group-wise Operation and Transformation(分组级运算和转换)

    4.Pivot Tables and Cross-Tabulation(透视表和交叉表)

    本文是第一部分,介绍groupby技术。

    一、分组原理

    核心:

    1.不论分组键是数组、列表、字典、Series、函数,只要其与待分组变量的轴长度一致都可以传入groupby进行分组。

    2.默认axis=0按行分组,可指定axis=1对列分组。

    对数据进行分组操作的过程可以概括为:split-apply-combine三步:

    1.按照键值(key)或者分组变量将数据分组。

    2.对于每组应用我们的函数,这一步非常灵活,可以是python自带函数,可以是我们自己编写的函数。

    3.将函数计算后的结果聚合。

    figure1

    图1:分组聚合原理(图片来自《Python for Data Analysis》page 252)

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

    figure2

    我们将key1当做我们的分组键值,对data1进行分组,再求每组的均值:

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

    语法很简单,但是这里需要注意grouped的数据类型,它不在是一个数据框,而是一个GroupBy对象。

    grouped

    figure3

    实际上,在这一步,我们并没有进行任何计算仅仅是创建用key1分组后创建了一个GroupBy对象,我们后面函数的任何操作都是基于这个对象的。

    求均值:

    grouped.mean()

    figure4

    刚刚我们只是用了key1进行了分组,我们也可以使用两个分组变量,并且通过unstack方法进行结果重塑:

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

    figure5

    means.unstack

    figure6

    以上我们的分组变量都是df内部的Series,实际上只要是和key1等长的数组也可以:

    states = np.array(['Ohio', 'California', 'California', 'Ohio', 'Ohio'])
    years = np.array([2005, 2005, 2006, 2005, 2006])
    df['data1'].groupby([states, years]).mean()

    figure6

    二、对分组进行迭代

    GroupBy对象支持迭代操作,会产生一个由分组变量名和数据块组成的二元元组:

    for name, group in df.groupby('key1'):
        print name
        print group

    figure7

    如果分组变量有两个:

    for (k1,k2), group in df.groupby(['key1','key2']):
        print k1,k2
        print group

    figure8

    我们可以将上面的结果转化为list或者dict,来看看结果是什么样的:

    list(df.groupby(['key1','key2']))

    figure9

    看不太清楚,我们来看看这个列表的第一个元素:

    list(df.groupby(['key1','key2']))[0]

    figure10

    同样,我们也可以将结果转化为dict(字典):

    dict(list(df.groupby(['key1','key2'])))

    figure11

    dict(list(df.groupby(['key1','key2'])))[('a','one')]

    figure12

    以上都是基于行进行分组,因为默认情况下groupby是在axis=0方向(行方向)进行分组,我们可以指定axis=1方向(列方向)进行分组:

    grouped=df.groupby(df.dtypes,axis=1)
    list(grouped)[0]

    figure13

    dict(list(grouped))

    figure14

    注意,

    '''下面两段语句功能一样'''
    df.groupby('key1')['data1']
    df.data1.groupby(df.key1)

    三、通过字典进行分组

    people = pd.DataFrame(np.random.randn(5, 5),
         columns=['a', 'b', 'c', 'd', 'e'],
         index=['Joe', 'Steve', 'Wes', 'Jim', 'Travis'])
    people.ix[2:3, ['b', 'c']] = np.nan # 添加缺失值
    people

    figure15

    假如,我们想按列进行聚合,该怎么操作呢?

    我们根据实际情况,对列名建立字典,然后将此字典传入groupby,切记指定axis=1,因为我们是对列进行分组聚合:

    mapping = {'a': 'red', 'b': 'red', 'c': 'blue',
         'd': 'blue', 'e': 'red', 'f' : 'orange'}
    by_columns=people.groupby(mapping,axis=1)
    by_columns.mean()

    figure16

    既然我们可以通过传入字典来对列进行分组,那么肯定也可以通过传入Series来对列进行分组了(Series中的index就相当字典中的key嘛):

    map_series = pd.Series(mapping)
    people.groupby(map_series,axis=1).count()

    figure17

    四、通过函数进行分组

    刚刚我们分组时利用了dict和series建立映射,对于一些复杂的需求,我们可以直接对groupby函数传递函数名来进行分组,以刚才的people数据为例,如果我们想按行分组,分组的key是每个人名的字母长度,该怎么做呢?比较直接的想法是相对每个名字求长度,建立一个数组,然后将这个数组传入groupby,我们来试验一下:

    l=[len(x) for x in people.index]
    people.groupby(l).count()

    figure18

    方案可行,那么有没有更快捷更优美的方法呢?当然有啦,我们只需将len这个函数名传给groupby即可:

    people.groupby(len).count()

    figure18

    除了传递函数,我们也可以将函数和dict,series,array一起使用,毕竟最后都会统统转化为数组:

    key_list = ['one', 'one', 'one', 'two', 'two']
    people.groupby([len, key_list]).min()

    figure19

    五、根据索引级别分组

    刚刚我们的数据索引只有一级,当数据有多级索引时,可以通过level指定我们想要分组的索引,注意要使用axis=1表示按列:

    columns = pd.MultiIndex.from_arrays([['Asian', 'Asian', 'Asian', 'America', 'America'],
        ['China','Japan','Singapore','United States','Canada']], names=['continent', 'country'])
    hier_df = pd.DataFrame(np.random.randn(4, 5), columns=columns)
    hier_df

    figure19

    我们按洲进行分组求和:

    figure20

  • 相关阅读:
    正则表达式验证手机号
    windows redis 安装启动及设置密码
    c# MVC利用AuthorizeAttribute验证用户是否登录
    判断页面是否加载完成
    关于List的ConcurrentModificationException
    intellij idea 12 编码不可映射字符
    这年头,竞争压力这么大,为什么我啥都想学。
    关于学习
    盘点8种CSS实现垂直居中水平居中的绝对定位居中技术
    单点登录原理与简单实现
  • 原文地址:https://www.cnblogs.com/zhangzhangwhu/p/7219651.html
Copyright © 2011-2022 走看看