python笔记 - 分组相关函数

这篇笔记主要是关于pandas中三个函数groupby()、crosstab()、pivot_table(),平常做数据统计表时会经常使用。

一、groupby()


  1. 基本使用
# 对一列进行分组
df['data1'].groupby(df['key1’]).mean() # 结果是series
df[['data1','data2']].groupby(df['key1']).sum()  # 结果是dataframe                     

df.groupby('key1’)['data1'].mean() # 结果是series
# 设置参数as_index=False,可避免分组键组成索引,如果结果列是单列,要写成df.groupby才能使用as_index
df.groupby('key1',as_index = False)['data1'].sum() # 图2 结果是dataframe形式  
df.groupby('key1’)[['data1','data2']].mean() # 结果是dataframe形式

# 默认所有数值列都要被聚合
df.groupby('key1').mean()

# 对两列进行分组,出来的结果,索引是具有层次化的两列
means = df['data1'].groupby([df['key1'], df['key2']]).mean() #结果是series
means.unstack() #把内层的索引抽出来成为列,结果是DataFrame

# 多列分组多列结果
df.groupby(['key1','key2'])[['data1','data2']].mean()
           
# 返回分组大小
df.groupby(['key1', 'key2']).size()

# 聚合函数使用自定义函数
df.groupby('key1').agg(lambda x: x.max()-x.min())
--------------------------           
# 自定义分组
key = list('ototo') # 要和行的数量一致
df.groupby(key).mean()
# 结果
      data1     data2
o -0.211108  0.162019
t -0.354277 -0.845506
           
--------------------------
# 使用describe()
df.groupby('key1')['data1'].describe()
      count      mean       std       min       25%       50%       75%  \
key1                                                                      
a       4.0  0.263429  0.948813 -0.786293 -0.160546  0.165381  0.589355   
b       4.0  0.464058  1.447415 -1.146518 -0.137997  0.318070  0.920126   
c       3.0 -0.444718  0.527141 -1.053396 -0.598537 -0.143678 -0.140379   

           max  
key1            
a     1.509245  
b     2.366611  
c    -0.137080  
# 转置
df.groupby('key1')['data1'].describe().T
key1          a         b         c
count  4.000000  4.000000  3.000000
mean   0.263429  0.464058 -0.444718
std    0.948813  1.447415  0.527141
min   -0.786293 -1.146518 -1.053396
25%   -0.160546 -0.137997 -0.598537
50%    0.165381  0.318070 -0.143678
75%    0.589355  0.920126 -0.140379
max    1.509245  2.366611 -0.137080           
           
  1. 分组使用不同聚合函数
# 多列使用多个一样的聚合函数
df.groupby(['key1'])[['data1','data2']].agg(['count', 'mean', 'max'])

# 多列对应多个聚合函数,不同列对应不同的聚合函数
df.groupby(['key1'])[['data1','data2']].agg({'data1':'sum','data2':'mean'})

# 显示分组结果时,给聚合函数取别名
ftuples = [('平均数', 'mean'),('总和', 'sum')]  #注意是元组的形式
df.groupby(['key1'])[['data1','data2']].agg(ftuples)
  1. 结合transform使用

    注意:使用transform返回的数据大小和原始的df大小一样(行列)

df
# 结果
  key1 key2     data1     data2
0    a  one  0.112262 -0.993748
1    a  two -0.449957 -0.580374
2    b  one  0.560749 -0.202874
3    b  two -0.258597 -1.110639
4    a  one -1.306336  1.682677
----------------
df.groupby('key1').mean()
# 结果
         data1     data2
key1                    
a    -0.548010  0.036185
b     0.151076 -0.656756
----------------
# groupby结合transform使用
df.groupby('key1').transform(np.mean)
# 结果 和原始的df行数相同,并生成的是对应的组的均值
      data1     data2
0 -0.548010  0.036185
1 -0.548010  0.036185
2  0.151076 -0.656756
3  0.151076 -0.656756
4 -0.548010  0.036185
# 和group合并,实现在原表基础上添加列存放所属组均值的列,也可以使用df和普通的groupby做merge实现
pd.concat([df,meanData], axis = 1)
#结果
  key1 key2     data1     data2     data1     data2
0    a  one  0.112262 -0.993748 -0.548010  0.036185
1    a  two -0.449957 -0.580374 -0.548010  0.036185
2    b  one  0.560749 -0.202874  0.151076 -0.656756
3    b  two -0.258597 -1.110639  0.151076 -0.656756
4    a  one -1.306336  1.682677 -0.548010  0.036185

4、结合apply使用

​ 将待处理对象拆分为多个对象-->对每一个对象应用函数-->最后合并数据

​ 每个组的大小,取决于apply中的函数返回,可以返回多值。(区别于groupby中默认使用聚合函数)

df
#
key1 key2     data1     data2
0     a  one  0.282725 -0.961001
1     a  two -0.786293  1.067054
2     b  one  0.437965 -0.470522
3     b  two  0.198176  2.503218
4     a  one  1.509245  0.714996
5     a  one  0.048036 -0.058840
6     b  two -1.146518 -1.049952
7     c  one -0.143678 -1.182260
8     c  two -1.053396 -0.301872
9     b  one  2.366611  0.419086
10    c  one -0.137080 -0.914790
---------------
# 取每组按某列排最大的n个
def top(df,n=3,column = 'data1'):
    return df.sort_values(by = column)[-n:]

df.groupby('key1').apply(top,n=2)
#
        key1 key2     data1     data2
key1                                 
a    0     a  one  0.282725 -0.961001
     4     a  one  1.509245  0.714996
b    2     b  one  0.437965 -0.470522
     9     b  one  2.366611  0.419086
c    7     c  one -0.143678 -1.182260
     10    c  one -0.137080 -0.914790

二、pivot_table()


1.定义:

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

2.参数:

values: 可选参数,用来做集合的值,默认是显示所有的值。

index:必选参数,用来指定行索引。如果用数组做行索引,数据必须等长。

columns:必选参数,用来指定列索引。

aggfunc:聚合函数,默认是 np.mean , 支持numpy 的计算方法

fill_value:填充NA值。默认不填充

margins:添加行列的总计,默认不显示。

dropna:如果整行都为NA值,则进行丢弃,默认丢弃。

margins_name:在margins参数为ture时,用来修改margins的名称

3.使用

tips.head(10)
   total_bill   tip     sex smoker  day    time  size   tip_pct
0       16.99  1.01  Female     No  Sun  Dinner     2  0.059447
1       10.34  1.66    Male     No  Sun  Dinner     3  0.160542
2       21.01  3.50    Male     No  Sun  Dinner     3  0.166587
3       23.68  3.31    Male     No  Sun  Dinner     2  0.139780
4       24.59  3.61  Female     No  Sun  Dinner     4  0.146808
5       25.29  4.71    Male     No  Sun  Dinner     4  0.186240
6        8.77  2.00    Male     No  Sun  Dinner     2  0.228050
7       26.88  3.12    Male     No  Sun  Dinner     4  0.116071
8       15.04  1.96    Male     No  Sun  Dinner     2  0.130319
9       14.78  3.23    Male     No  Sun  Dinner     2  0.218539

------------------------
# 1.普通透视表,设定index
tips.pivot_table(index=['sex','smoker'])
# 结果
                   size       tip   tip_pct  total_bill
sex    smoker
Female No      2.592593  2.773519  0.156921   18.105185
       Yes     2.242424  2.931515  0.182150   17.977879
Male   No      2.711340  3.113402  0.160669   19.791237
       Yes     2.500000  3.051167  0.152771   22.284500
------------------------
# 2.多层透视表
tips.pivot_table( values = ['tip_pct','size'], index = ['sex','day'],columns ='smoker')
# 结果
                 size             tip_pct
smoker             No       Yes        No       Yes
sex    day
Female Fri   2.500000  2.000000  0.165296  0.209129
       Sat   2.307692  2.200000  0.147993  0.163817
       Sun   3.071429  2.500000  0.165710  0.237075
       Thur  2.480000  2.428571  0.155971  0.163073
Male   Fri   2.000000  2.125000  0.138005  0.144730
       Sat   2.656250  2.629630  0.162132  0.139067
       Sun   2.883721  2.600000  0.158291  0.173964
       Thur  2.500000  2.300000  0.165706  0.164417
------------------------      
# 添加margins,多加一个ALL列,不考虑分组级别中的差异
tips.pivot_table( ['tip_pct','size'], index = ['sex','day'],columns ='smoker', margins = True)
# 结果
                 size                       tip_pct
smoker             No       Yes       All        No       Yes       All
sex    day
Female Fri   2.500000  2.000000  2.111111  0.165296  0.209129  0.199388
       Sat   2.307692  2.200000  2.250000  0.147993  0.163817  0.156470
       Sun   3.071429  2.500000  2.944444  0.165710  0.237075  0.181569
       Thur  2.480000  2.428571  2.468750  0.155971  0.163073  0.157525
Male   Fri   2.000000  2.125000  2.100000  0.138005  0.144730  0.143385
       Sat   2.656250  2.629630  2.644068  0.162132  0.139067  0.151577
       Sun   2.883721  2.600000  2.810345  0.158291  0.173964  0.162344
       Thur  2.500000  2.300000  2.433333  0.165706  0.164417  0.165276
All          2.668874  2.408602  2.569672  0.159328  0.163196  0.160803
-------------------------
# 添加fill_value,aggfunc
tips.pivot_table('size',index=['time','sex','smoker'],columns='day',aggfunc='sum', fill_value=0)
# 结果
day                   Fri  Sat  Sun  Thur
time   sex    smoker
Dinner Female No        2   30   43     2
              Yes       8   33   10     0
       Male   No        4   85  124     0
              Yes      12   71   39     0
Lunch  Female No        3    0    0    60
              Yes       6    0    0    17
       Male   No        0    0    0    50
              Yes       5    0    0    23

三、crosstab()


交叉表,计算分组频率的特殊透视表,相当于pivot_table()中aggfunc参数默认为count

In [21]: data
Out[21]:
   Sample  Gender    Handedness
0       1  Female  Right-handed
1       2    Male   Left-handed
2       3  Female  Right-handed
3       4    Male  Right-handed
4       5    Male   Left-handed
5       6    Male  Right-handed
6       7  Female  Right-handed
7       8  Female   Left-handed
8       9    Male  Right-handed
9      10  Female  Right-handed

# 简单交叉表实现,只接收两个参数时,将提供一个频率表。
In [22]: pd.crosstab(data['Gender'],data['Handedness'])
Out[22]:
Handedness  Left-handed  Right-handed
Gender
Female                1             4
Male                  2             3

# 添加margins
In [23]: pd.crosstab(data.Gender,data.Handedness, margins=True)
Out[23]:
Handedness  Left-handed  Right-handed  All
Gender
Female                1             4    5
Male                  2             3    5
All                   3             7   10

# 添加normalize,设置百分比
pd.crosstab(nf['A'],nf['B'],normalize=True)

# 其他还有些参数和pivot_table()使用方法差不多。

猜你喜欢

转载自www.cnblogs.com/nico-co/p/12803573.html