• pandas之groupby分组与pivot_table透视


    一、groupby

    类似excel的数据透视表,一般是按照行进行分组,使用方法如下。

    df.groupby(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=True,
            squeeze=False, observed=False, **kwargs)

    分组得到的直接结果是一个DataFrameGroupBy对象。

    df = pd.DataFrame({'A':['zhao','li','wang','li','zhao'],
                       'B':['one','one','two','three','two'],
                       'C':np.arange(1,6),
                       'D':np.arange(6,11)})
    print(df)
    print(df.groupby('A'))
    print(type(df.groupby('A')))
    #       A      B  C   D
    # 0  zhao    one  1   6
    # 1    li    one  2   7
    # 2  wang    two  3   8
    # 3    li  three  4   9
    # 4  zhao    two  5  10
    # <pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000000001E6C550>
    # <class 'pandas.core.groupby.generic.DataFrameGroupBy'>

    分组后的直接结果是一个可迭代对象,可迭代对象中的每一个元素都是一个元组,元组的第一个值为分组的名称,第二个值为DataFrame。可通过for或转换为list、元组查看每一个元素。

    for n,p in df.groupby('A'):
        print(type(p))
        print(n)
        print(p)
        print('-------------------------')
    # <class 'pandas.core.frame.DataFrame'>
    # li
    #     A      B  C  D
    # 1  li    one  2  7
    # 3  li  three  4  9
    # -------------------------
    # <class 'pandas.core.frame.DataFrame'>
    # wang
    #       A    B  C  D
    # 2  wang  two  3  8
    # -------------------------
    # <class 'pandas.core.frame.DataFrame'>
    # zhao
    #       A    B  C   D
    # 0  zhao  one  1   6
    # 4  zhao  two  5  10
    # -------------------------
    查看分组后的结果

    通过get_group('分组名称')获取某一个分组的内容

    groups是一个字典,字典的键为各分组名称,值为列表包含分组所在的索引行,可通过groups['分组名称']查看某一个分组所在的行

    print(df.groupby('A').get_group('zhao'))  #获取分组后的zhao组
    #       A    B  C   D
    # 0  zhao  one  1   6
    # 4  zhao  two  5  10
    
    print(df.groupby(['A','B']).groups)
    print(df.groupby(['A','B']).groups[('li', 'one')])
    # {('li', 'one'): Int64Index([1], dtype='int64'), ('li', 'three'): Int64Index([3], dtype='int64'), ('wang', 'two'): Int64Index([2], dtype='int64'), ('zhao', 'one'): Int64Index([0], dtype='int64'), ('zhao', 'two'): Int64Index([4], dtype='int64')}
    # Int64Index([1], dtype='int64')
    get_group查看分组内容和groups查看分组所在行

    size( )统计每个分组的长度

    print(df.groupby('A').size())
    print(type(df.groupby('A').size()))
    # A
    # li      2
    # wang    1
    # zhao    2
    # dtype: int64
    # <class 'pandas.core.series.Series'>
    size统计分组的长度

    分组可对单列或者多列进行,如果对多列进行分组,需要写在一个列表内。

    df = pd.DataFrame({'A':['zhao','li','wang','li','zhao'],
                       'B':['one','one','two','three','two'],
                       'C':np.arange(1,6),
                       'D':np.arange(6,11)})
    print(df.groupby('A').sum())   #以A列分组,对其他元素为数值的列进行求和,忽略非数值元素的列
    print('---------------------')
    print(df.groupby(['A','B']).sum())   #以A列和B列分组,对其他列求和,忽略非数值元素的列
    print('---------------------')
    print(df.groupby('A')['D'].sum())   #以A列分组,再对D列求和
          C   D
    # A          
    # li    6  16
    # wang  3   8
    # zhao  6  16
    # ---------------------
    #             C   D
    # A    B           
    # li   one    2   7
    #      three  4   9
    # wang two    3   8
    # zhao one    1   6
    #      two    5  10
    # ---------------------
    # A
    # li      16
    # wang     8
    # zhao    16
    # Name: D, dtype: int32
    groupby单列和多列分组

    按照index分组,将index相同的分为一组,分组依据level=0

    df = pd.DataFrame({'data1':[1,2,3,4],'data2':[3,4,5,6],'A':[5,6,7,8],'B':[7,8,9,0]},index=[1,2,3,1])
    print(df)  #groupby(level=0)表示将索引相同的行分为一组
    print(df.groupby(level=0).first()) #分组后组内第一个值
    print(df.groupby(level=0).last())  #分组后组内最后一个值
    print(df.groupby(level=0).max())   #分组后组内最大值
    print(df.groupby(level=0).min())   #分组后组内最小值
    print(df.groupby(level=0).sum())   #分组后组内元素的和
    print(df.groupby(level=0).mean())  #分组后组内元素的平均值
    print(df.groupby(level=0).median())#分组后组内元素的中位数
    print(df.groupby(level=0).count())   #分组后组内元素的个数
    print(df.groupby(level=0).std())     #分组后组内元素的方差
    print(df.groupby(level=0).prod())    #分组后组内元素的乘积
    print(df.groupby(level=0).describe())#分组后组内元素的count、mean、std、min、25%、50%、75%。max
    按index分组

    按照index长度分组

    df = pd.DataFrame({'A':[1,2,3,4],'B':[3,4,5,6],'D':[5,6,7,8],'D':[7,8,9,0]},index=['a','ab','cd','e'])
    print(df)
    print(df.groupby(len).sum())
    #     A  B  D
    # a   1  3  7
    # ab  2  4  8
    # cd  3  5  9
    # e   4  6  0
    #    A  B   D
    # 1  5  9   7
    # 2  5  9  17
    按照index长度分组

    按照数据类型进行分组,df.dtypes可获得每个数据列的数据类型,数据类型是对列而言,因此按数据类型分组需指明axis=1

    df = pd.DataFrame({'data1':[1,2],'data2':[3,4],'A':['a','b'],'B':['c','d']})
    print(df)
    print(df.groupby(df.dtypes,axis=1).sum())
    for n,p in df.groupby(df.dtypes,axis=1):
        print(n)
        print(p)
        print('-------')
    #    data1  data2  A  B
    # 0      1      3  a  c
    # 1      2      4  b  d
    #    int64 object
    # 0      4     ac
    # 1      6     bd
    # int64
    #    data1  data2
    # 0      1      3
    # 1      2      4
    # -------
    # object
    #    A  B
    # 0  a  c
    # 1  b  d
    # -------
    按照数据类型dtypes分组

    按照字典分组,需定义一个字典,键为列名称,值为对应的分组名称,按照列分组需要指明axis=1

    例如下面例子中的map,定义data1列和A列属于分组key1,data2列数组分组key2,B列属于分组key3

    df = pd.DataFrame({'data1':[1,2],'data2':[3,4],'A':['a','b'],'B':['c','d']})
    map = {'data1':'key1','data2':'key2','A':'key1','B':'key3'}
    for i,p in df.groupby(map,axis=1):
        print(i)
        print(p)
        print('----------')
    # key1
    #    data1  A
    # 0      1  a
    # 1      2  b
    # ----------
    # key2
    #    data2
    # 0      3
    # 1      4
    # ----------
    # key3
    #    B
    # 0  c
    # 1  d
    # ----------
    按照字典分组

    多函数计算agg(函数1,函数2)

    对分组后的每个组既进行第一个函数的计算,又进行第二个函数的计算。

    df = pd.DataFrame({'a':[1,2,3,1],'b':['a','b','a','b'],'c':np.arange(3,7),'d':np.arange(2,6)})
    print(df)
    print(df.groupby('a').agg(['mean','sum']))  #b列为非数值,忽略
    print(df.groupby('b').agg([np.sum,np.mean]))
    #    a  b  c  d
    # 0  1  a  3  2
    # 1  2  b  4  3
    # 2  3  a  5  4
    # 3  1  b  6  5
    #      c        d
    #   mean sum mean sum
    # a
    # 1  4.5   9  3.5   7
    # 2  4.0   4  3.0   3
    # 3  5.0   5  4.0   4
    #     a        c        d
    #   sum mean sum mean sum mean
    # b
    # a   4  2.0   8    4   6    3
    # b   3  1.5  10    5   8    4
    分组后多函数计算agg

    多函数计算后的默认column为函数名称,也可以通过字典自定义column。

    df = pd.DataFrame({'a':[1,2,3,1],'b':['a','b','a','b'],'c':np.arange(3,7),'d':np.arange(2,6)})
    print(df.groupby('b')['c'].agg({'result_sum':np.sum,'result_mean':np.mean}))
    #    result_sum  result_mean
    # b                         
    # a           8            4
    # b          10            5
    多函数计算后自定义列名称

    二、transform

    上述groupby如果通过行分组再进行求和、均值等,会出现结果与原对象的行数不一致的情况,而通过transform得到的结果与原对象的结果行数一致。

    df = pd.DataFrame({'A':['zhao','li','wang','li','zhao'],
                       'B':['one','one','two','two','three'],
                       'C':np.arange(1,6),
                       'D':np.arange(5,10)})
    print(df)
    print(df.groupby('B').mean())  #只包含one、two、three三行
    print(df.groupby('B').transform(np.mean))  #结果为5行,B列内容相同的行的结果相同
    #       A      B  C  D
    # 0  zhao    one  1  5
    # 1    li    one  2  6
    # 2  wang    two  3  7
    # 3    li    two  4  8
    # 4  zhao  three  5  9
    #          C    D
    # B              
    # one    1.5  5.5
    # three  5.0  9.0
    # two    3.5  7.5
    #      C    D
    # 0  1.5  5.5
    # 1  1.5  5.5
    # 2  3.5  7.5
    # 3  3.5  7.5
    # 4  5.0  9.0
    transform()演示

    三、applay

    上述groupby分组后都是使用python定义好的sum、mean、max等进行统计计算,apply可以自定义统计方法。

    def func(df,n):
        return ***
    
    df.groupby('*').apply(func,n)
    
    #自定义函数func,第一个参数为pandas对象,并返回值
    #分组后使用apply函数,将自定义函数的名称作为第一个参数,第二个参数传递给自定义函数的第二个参数
    df = pd.DataFrame({'A':['zhao','li','wang','li','zhao','zhao'],
                       'B':['one','one','two','two','three','two'],
                       'C':np.arange(1,7),
                       'D':np.arange(4,10)})
    def f(d,n):
        return d.sort_index()[:n]  #按照索引排序,并返回前n行
    print(df)
    print(df.groupby('A').apply(f,2))  #按照A分组,对结果按索引排序,并返回每组的前n行
          A      B  C  D
    # 0  zhao    one  1  4
    # 1    li    one  2  5
    # 2  wang    two  3  6
    # 3    li    two  4  7
    # 4  zhao  three  5  8
    # 5  zhao    two  6  9
    #            A      B  C  D
    # A                        
    # li   1    li    one  2  5
    #      3    li    two  4  7
    # wang 2  wang    two  3  6
    # zhao 0  zhao    one  1  4
    #      4  zhao  three  5  8
    apply()自定义统计方法

    四、透视表pivot_table()、pivot()

    pivot_table(self, values=None, index=None, columns=None, aggfunc='mean', 
                fill_value=None, margins=False, dropna=True, margins_name='All')

    可类比excel的数据透视表进行理解,使用方法pd.pivot_table( df , ...),或直接使用df.pivot_table( ... )

    • values:透视后对哪一列进行计算
    • index:按照哪一列进行分组
    • columns:透视后除了values,还包含哪些列
    • aggfunc:对values进行计算的方法,默认为平均值
    • fill_value:对空值使用fill_value指定的值填充,默认为NaN
    import numpy as np
    import pandas as pd
    date = ['2019/5/1','2019/5/2','2019/5/3']*3
    df = pd.DataFrame({'date':pd.to_datetime(date),'key':list('abcbacbca'),'value':np.arange(1,10)})
    print(df)
    print(df.pivot_table(index='date',values='value',columns='key',aggfunc=np.sum))
    print(df.pivot_table(index=['date','key'],values='value',aggfunc=np.sum))
    #         date key  value
    # 0 2019-05-01   a      1
    # 1 2019-05-02   b      2
    # 2 2019-05-03   c      3
    # 3 2019-05-01   b      4
    # 4 2019-05-02   a      5
    # 5 2019-05-03   c      6
    # 6 2019-05-01   b      7
    # 7 2019-05-02   c      8
    # 8 2019-05-03   a      9
    # key           a     b    c
    # date                      
    # 2019-05-01  1.0  11.0  NaN
    # 2019-05-02  5.0   2.0  8.0
    # 2019-05-03  9.0   NaN  9.0
    #                 value
    # date       key       
    # 2019-05-01 a        1
    #            b       11
    # 2019-05-02 a        5
    #            b        2
    #            c        8
    # 2019-05-03 a        9
    #            c        9
    数据透视表pivot_table()

    pivot()也是用来生成透视表的,结果为一个二维的表格,结果中可能会存在空值,但是与pivot_table()用法和结果稍有不同。

    pivot(data, index=None, columns=None, values=None),使用方法pd.pivot(df,...)或者df.pivot()

    index 透视行

    columns 透视列

    values 对哪一列进行透视

    date = ['2019/5/1','2019/5/2','2019/5/3']*3
    df = pd.DataFrame({'date':pd.to_datetime(date),'key':list('abcbabccd'),'value':np.arange(1,10)})
    res = pd.pivot(df,'date','key','value')
    print(res)
    # key           a    b    c    d
    # date                          
    # 2019-05-01  1.0  4.0  7.0  NaN
    # 2019-05-02  5.0  2.0  8.0  NaN
    # 2019-05-03  NaN  6.0  3.0  9.0
    数据透视pivot()

    五、交叉表crossta()

     交叉表默认用来统计元素出现的频数,使用方法pd.crosstab(Seris1,Seris2)

    crosstab(index, columns, values=None, rownames=None, colnames=None, aggfunc=None, 
          margins=False, margins_name='All', dropna=True, normalize=False)
    • index:行的统计依据
    • columns:列的统计依据
    • values:在行为index、列为columns的基础上,对values指定的列进行统计,默认为None,表示统计频数
    • aggfunc:统计方法,agggunc和values必须同时使用
    • normalize:默认为False,值设置为True表示统计频率
    • margins:默认为False,值设置为True表示对结果添加一列,对每列的和进行统计,同时添加一行,对每行的和进行统计
    • rownames和colnames:默认为None,即显示index和columns的名称
    df = pd.DataFrame([[1,2,3,1,3],[2,'a','a',2,1],[3,np.nan,'a','b',2],[np.nan,'a','b',1,2],[4,1,'c','b',2]],columns=['A','B','C','D','E'])
    print(pd.crosstab(df['A'],df['B']))   #表示统计A为1且B为1出现的次数,A为2且B为1出现的次数,A为4且B为1出现的次数……
    # B    1  2  a
    # A
    # 1.0  0  1  0
    # 2.0  0  0  1
    # 4.0  1  0  0

    可以看到A为np.nan、B为np.nan的两行在统计时都被忽略了。

    normalize=True会将上述结果的非0值显示为小数试的百分比

    print(pd.crosstab(df['A'],df['B'],normalize=True))
    # B           1         2         a
    # A                                
    # 1.0  0.000000  0.333333  0.000000
    # 2.0  0.000000  0.000000  0.333333
    # 4.0  0.333333  0.000000  0.000000

    同时指定values=df['E']和aggfunc=np.sum,表示在A和B对应值得条件下,对E列求和

    print(pd.crosstab(df['A'],df['B'],values=df['E'],aggfunc=np.sum))
    # B    1  2  a
    # A           
    # 1.0  0  1  0
    # 2.0  0  0  1
    # 4.0  1  0  0

    margins增加行和列的总数统计

    print(pd.crosstab(df['A'],df['B']))   
    print(pd.crosstab(df['A'],df['B'],margins=True))
    # B    1  2  a
    # A
    # 1.0  0  1  0
    # 2.0  0  0  1
    # 4.0  1  0  0
    
    # B    1  2  a  All
    # A                
    # 1.0  0  1  0    1
    # 2.0  0  0  1    1
    # 4.0  1  0  0    1
    # All  1  1  1    3

    rownames和colnames自定义结果显示的行和列名称

    print(pd.crosstab(df['A'],df['B'],rownames=['AAA'],colnames=['BBB']))
    # BBB  1  2  a
    # AAA
    # 1.0  0  1  0
    # 2.0  0  0  1
    # 4.0  1  0  0
  • 相关阅读:
    012——matlab判断变量是否存在
    011——MATLAB清除工作控件变量
    014——C#新建文件夹
    征服django的关键内容
    Django中session的使用
    RabbitMq与Redis的使用
    python的命名规则
    python类的深层次理解
    python类总结
    python之paramiko模块
  • 原文地址:https://www.cnblogs.com/Forever77/p/11288682.html
Copyright © 2020-2023  润新知