pandas组队学习-Task3 分组方法groupby()和它的小伙伴们

目录

1. 学习内容

2. 什么是SAC过程

3. 准备工作

4. groupby()方法

4.1 一般用法

4.1.1 按某一列分组

4.1.2 按多列分组

4.1.3 查看每一组的容量和分成的组数

4.1.4 遍历每一组

4.1.5 level参数和axis参数

4.2 groupby对象的特点

4.2.1 可用的方法

4.2.2 head()方法和firtst()方法

4.2.3 自定义分组依据

4.2.4 groupby()的[]操作

4.2.5 用groupby()对连续型变量进行分组

5. groupby()的小伙伴们:agg(), filter(), transform()和apply()方法

5.1 聚合方法agg()

5.1.1 同时使用多个聚合函数

5.1.2 对聚合结果的列重命名

5.1.3 指定哪些列做哪种聚合

5.1.4 自定义聚合函数

5.2 过滤方法filter()

5.3 变换方法transform()

5.3.1 传入参数

5.3.2 利用变换进行组内标准化

5.3.3 利用变换进行组内缺失值处理

5.4 应用方法apply()

5.4.1 apply()方法的灵活性

5.4.2 用apply()方法同时统计多个统计量

6. 问题与练习

6.1 问题

6.2 练习

7. 参考文献

1. 学习内容

1. 了解什么是SAC过程

2. 学习如何利用groupby()实现对表格的分组

3. 学习如何在分组的基础上进行进一步的数据处理

本项目参见https://github.com/datawhalechina/team-learning/tree/master/Pandas%E6%95%99%E7%A8%8B%EF%BC%88%E4%B8%8A%EF%BC%89

2. 什么是SAC过程

SAC指的是分组操作中的split-apply-combine过程。其中,split指基于某一些规则,将数据拆成若干组;apply是指对每一组独立地使用函数;而combine指将每一组的结果组合成某一类新的数据结构。

那么在pandas中,这一套操作是如何完成的呢?首先,split即分组操作由groupby()来实现;然后,apply操作由agg()、filter()、transform()和apply()方法实现;最后,combine操作由concat()函数实现。在这里,我们只讨论前两个操作。

3. 准备工作

import numpy as np
import pandas as pd
df = pd.read_csv(r'./data/table.csv',index_col = 'ID')
print(df.head())
     School Class Gender   Address  Height  Weight  Math Physics
ID                                                              
1101    S_1   C_1      M  street_1     173      63  34.0      A+
1102    S_1   C_1      F  street_2     192      73  32.5      B+
1103    S_1   C_1      M  street_2     186      82  87.2      B+
1104    S_1   C_1      F  street_2     167      81  80.4      B-
1105    S_1   C_1      F  street_4     159      64  84.8      B+

4. groupby()方法

4.1 一般用法

4.1.1 按某一列分组

表格经过groupby()分组处理后会生成一个groupby对象。该对象本身不会返回任何东西,只有当相应的方法被调用才会起作用。

grouped_single = df.groupby('School')
print(grouped_single.get_group('S_1').head())
     School Class Gender   Address  Height  Weight  Math Physics
ID                                                              
1101    S_1   C_1      M  street_1     173      63  34.0      A+
1102    S_1   C_1      F  street_2     192      73  32.5      B+
1103    S_1   C_1      M  street_2     186      82  87.2      B+
1104    S_1   C_1      F  street_2     167      81  80.4      B-
1105    S_1   C_1      F  street_4     159      64  84.8      B+

4.1.2 按多列分组

grouped_mul = df.groupby(['School', 'Class'])
print(grouped_mul.get_group(('S_2', 'C_4')))
     School Class Gender   Address  Height  Weight  Math Physics
ID                                                              
2401    S_2   C_4      F  street_2     192      62  45.3       A
2402    S_2   C_4      M  street_7     166      82  48.7       B
2403    S_2   C_4      F  street_6     158      60  59.7      B+
2404    S_2   C_4      F  street_2     160      84  67.7       B
2405    S_2   C_4      F  street_6     193      54  47.6       B

4.1.3 查看每一组的容量和分成的组数

print(grouped_single.size())
print(grouped_single.ngroups)
School
S_1    15
S_2    20
dtype: int64
2
print(grouped_mul.size())
print(grouped_mul.ngroups)
School  Class
S_1     C_1      5
        C_2      5
        C_3      5
S_2     C_1      5
        C_2      5
        C_3      5
        C_4      5
dtype: int64
7

4.1.4 遍历每一组

for name, group in grouped_single:
    print(name)
    print(group)
S_1
     School Class Gender   Address  Height  Weight  Math Physics
ID                                                              
1101    S_1   C_1      M  street_1     173      63  34.0      A+
1102    S_1   C_1      F  street_2     192      73  32.5      B+
1103    S_1   C_1      M  street_2     186      82  87.2      B+
1104    S_1   C_1      F  street_2     167      81  80.4      B-
1105    S_1   C_1      F  street_4     159      64  84.8      B+
1201    S_1   C_2      M  street_5     188      68  97.0      A-
1202    S_1   C_2      F  street_4     176      94  63.5      B-
1203    S_1   C_2      M  street_6     160      53  58.8      A+
1204    S_1   C_2      F  street_5     162      63  33.8       B
1205    S_1   C_2      F  street_6     167      63  68.4      B-
1301    S_1   C_3      M  street_4     161      68  31.5      B+
1302    S_1   C_3      F  street_1     175      57  87.7      A-
1303    S_1   C_3      M  street_7     188      82  49.7       B
1304    S_1   C_3      M  street_2     195      70  85.2       A
1305    S_1   C_3      F  street_5     187      69  61.7      B-
S_2
     School Class Gender   Address  Height  Weight  Math Physics
ID                                                              
2101    S_2   C_1      M  street_7     174      84  83.3       C
2102    S_2   C_1      F  street_6     161      61  50.6      B+
2103    S_2   C_1      M  street_4     157      61  52.5      B-
2104    S_2   C_1      F  street_5     159      97  72.2      B+
2105    S_2   C_1      M  street_4     170      81  34.2       A
2201    S_2   C_2      M  street_5     193     100  39.1       B
2202    S_2   C_2      F  street_7     194      77  68.5      B+
2203    S_2   C_2      M  street_4     155      91  73.8      A+
2204    S_2   C_2      M  street_1     175      74  47.2      B-
2205    S_2   C_2      F  street_7     183      76  85.4       B
2301    S_2   C_3      F  street_4     157      78  72.3      B+
2302    S_2   C_3      M  street_5     171      88  32.7       A
2303    S_2   C_3      F  street_7     190      99  65.9       C
2304    S_2   C_3      F  street_6     164      81  95.5      A-
2305    S_2   C_3      M  street_4     187      73  48.9       B
2401    S_2   C_4      F  street_2     192      62  45.3       A
2402    S_2   C_4      M  street_7     166      82  48.7       B
2403    S_2   C_4      F  street_6     158      60  59.7      B+
2404    S_2   C_4      F  street_2     160      84  67.7       B
2405    S_2   C_4      F  street_6     193      54  47.6       B
for name, group in grouped_mul:
    print(name)
    print(group)
('S_1', 'C_1')
     School Class Gender   Address  Height  Weight  Math Physics
ID                                                              
1101    S_1   C_1      M  street_1     173      63  34.0      A+
1102    S_1   C_1      F  street_2     192      73  32.5      B+
1103    S_1   C_1      M  street_2     186      82  87.2      B+
1104    S_1   C_1      F  street_2     167      81  80.4      B-
1105    S_1   C_1      F  street_4     159      64  84.8      B+
('S_1', 'C_2')
     School Class Gender   Address  Height  Weight  Math Physics
ID                                                              
1201    S_1   C_2      M  street_5     188      68  97.0      A-
1202    S_1   C_2      F  street_4     176      94  63.5      B-
1203    S_1   C_2      M  street_6     160      53  58.8      A+
1204    S_1   C_2      F  street_5     162      63  33.8       B
1205    S_1   C_2      F  street_6     167      63  68.4      B-
('S_1', 'C_3')
     School Class Gender   Address  Height  Weight  Math Physics
ID                                                              
1301    S_1   C_3      M  street_4     161      68  31.5      B+
1302    S_1   C_3      F  street_1     175      57  87.7      A-
1303    S_1   C_3      M  street_7     188      82  49.7       B
1304    S_1   C_3      M  street_2     195      70  85.2       A
1305    S_1   C_3      F  street_5     187      69  61.7      B-
('S_2', 'C_1')
     School Class Gender   Address  Height  Weight  Math Physics
ID                                                              
2101    S_2   C_1      M  street_7     174      84  83.3       C
2102    S_2   C_1      F  street_6     161      61  50.6      B+
2103    S_2   C_1      M  street_4     157      61  52.5      B-
2104    S_2   C_1      F  street_5     159      97  72.2      B+
2105    S_2   C_1      M  street_4     170      81  34.2       A
('S_2', 'C_2')
     School Class Gender   Address  Height  Weight  Math Physics
ID                                                              
2201    S_2   C_2      M  street_5     193     100  39.1       B
2202    S_2   C_2      F  street_7     194      77  68.5      B+
2203    S_2   C_2      M  street_4     155      91  73.8      A+
2204    S_2   C_2      M  street_1     175      74  47.2      B-
2205    S_2   C_2      F  street_7     183      76  85.4       B
('S_2', 'C_3')
     School Class Gender   Address  Height  Weight  Math Physics
ID                                                              
2301    S_2   C_3      F  street_4     157      78  72.3      B+
2302    S_2   C_3      M  street_5     171      88  32.7       A
2303    S_2   C_3      F  street_7     190      99  65.9       C
2304    S_2   C_3      F  street_6     164      81  95.5      A-
2305    S_2   C_3      M  street_4     187      73  48.9       B
('S_2', 'C_4')
     School Class Gender   Address  Height  Weight  Math Physics
ID                                                              
2401    S_2   C_4      F  street_2     192      62  45.3       A
2402    S_2   C_4      M  street_7     166      82  48.7       B
2403    S_2   C_4      F  street_6     158      60  59.7      B+
2404    S_2   C_4      F  street_2     160      84  67.7       B
2405    S_2   C_4      F  street_6     193      54  47.6       B

4.1.5 level参数和axis参数

grouped = df.set_index(['Gender','School']).groupby(level = 0, axis = 0)
for name, group in grouped:
    print(name)
    print(group)
F
              Class   Address  Height  Weight  Math Physics
Gender School                                              
F      S_1      C_1  street_2     192      73  32.5      B+
       S_1      C_1  street_2     167      81  80.4      B-
       S_1      C_1  street_4     159      64  84.8      B+
       S_1      C_2  street_4     176      94  63.5      B-
       S_1      C_2  street_5     162      63  33.8       B
       S_1      C_2  street_6     167      63  68.4      B-
       S_1      C_3  street_1     175      57  87.7      A-
       S_1      C_3  street_5     187      69  61.7      B-
       S_2      C_1  street_6     161      61  50.6      B+
       S_2      C_1  street_5     159      97  72.2      B+
       S_2      C_2  street_7     194      77  68.5      B+
       S_2      C_2  street_7     183      76  85.4       B
       S_2      C_3  street_4     157      78  72.3      B+
       S_2      C_3  street_7     190      99  65.9       C
       S_2      C_3  street_6     164      81  95.5      A-
       S_2      C_4  street_2     192      62  45.3       A
       S_2      C_4  street_6     158      60  59.7      B+
       S_2      C_4  street_2     160      84  67.7       B
       S_2      C_4  street_6     193      54  47.6       B
M
              Class   Address  Height  Weight  Math Physics
Gender School                                              
M      S_1      C_1  street_1     173      63  34.0      A+
       S_1      C_1  street_2     186      82  87.2      B+
       S_1      C_2  street_5     188      68  97.0      A-
       S_1      C_2  street_6     160      53  58.8      A+
       S_1      C_3  street_4     161      68  31.5      B+
       S_1      C_3  street_7     188      82  49.7       B
       S_1      C_3  street_2     195      70  85.2       A
       S_2      C_1  street_7     174      84  83.3       C
       S_2      C_1  street_4     157      61  52.5      B-
       S_2      C_1  street_4     170      81  34.2       A
       S_2      C_2  street_5     193     100  39.1       B
       S_2      C_2  street_4     155      91  73.8      A+
       S_2      C_2  street_1     175      74  47.2      B-
       S_2      C_3  street_5     171      88  32.7       A
       S_2      C_3  street_4     187      73  48.9       B
       S_2      C_4  street_7     166      82  48.7       B

4.2 groupby对象的特点

4.2.1 可用的方法

print([attr for attr in dir(grouped_single) if not attr.startswith('_')])
['Address', 'Class', 'Gender', 'Height', 'Math', 'Physics', 'School', 'Weight', 'agg', 
'aggregate', 'all', 'any', 'apply', 'backfill', 'bfill', 'boxplot', 'corr', 'corrwith', 
'count', 'cov', 'cumcount', 'cummax', 'cummin', 'cumprod', 'cumsum', 'describe', 'diff', 
'dtypes', 'expanding', 'ffill', 'fillna', 'filter', 'first', 'get_group', 'groups', 'head', 
'hist', 'idxmax', 'idxmin', 'indices', 'last', 'mad', 'max', 'mean', 'median', 'min', 
'ndim', 'ngroup', 'ngroups', 'nth', 'nunique', 'ohlc', 'pad', 'pct_change', 'pipe', 'plot', 
'prod', 'quantile', 'rank', 'resample', 'rolling', 'sem', 'shift', 'size', 'skew', 'std', 
'sum', 'tail', 'take', 'transform', 'tshift', 'var']

4.2.2 head()方法和firtst()方法

head()方法会输出每一组的前几条数据,first()方法会输出每一组的第一条数据。

print(grouped_single.head(2))
     School Class Gender   Address  Height  Weight  Math Physics
ID                                                              
1101    S_1   C_1      M  street_1     173      63  34.0      A+
1102    S_1   C_1      F  street_2     192      73  32.5      B+
2101    S_2   C_1      M  street_7     174      84  83.3       C
2102    S_2   C_1      F  street_6     161      61  50.6      B+
print(grouped_single.first())
       Class Gender   Address  Height  Weight  Math Physics
School                                                     
S_1      C_1      M  street_1     173      63  34.0      A+
S_2      C_1      M  street_7     174      84  83.3       C

4.2.3 自定义分组依据

groupby()分组的依据是非常自由的,只要是与数据框长度相同的列表即可。同时它也支持函数型分组。函数型分组传入的参数是索引,如果是多级索引则传入的是各级索引构成的元组。

# 相当于将np.random.choice(['a','b','c'],df.shape[0])当做新的一列进行分组
print(df.groupby(np.random.choice(['a', 'b', 'c'], \
                                  df.shape[0])).get_group('a').head())
     School Class Gender   Address  Height  Weight  Math Physics
ID                                                              
1301    S_1   C_3      M  street_4     161      68  31.5      B+
1302    S_1   C_3      F  street_1     175      57  87.7      A-
2102    S_2   C_1      F  street_6     161      61  50.6      B+
2103    S_2   C_1      M  street_4     157      61  52.5      B-
2204    S_2   C_2      M  street_1     175      74  47.2      B-
print(df[:10].groupby(lambda x: print(x)).head())
1101
1102
1103
1104
1105
1201
1202
1203
1204
1205
     School Class Gender   Address  Height  Weight  Math Physics
ID                                                              
1101    S_1   C_1      M  street_1     173      63  34.0      A+
1102    S_1   C_1      F  street_2     192      73  32.5      B+
1103    S_1   C_1      M  street_2     186      82  87.2      B+
1104    S_1   C_1      F  street_2     167      81  80.4      B-
1105    S_1   C_1      F  street_4     159      64  84.8      B+
df.groupby(lambda x: '奇数行' if not df.index.get_loc(x) % 2 == 1 else '偶数行').groups
{'偶数行': Int64Index([1102, 1104, 1201, 1203, 1205, 1302, 1304, 2101, 2103, 2105, 2202,
             2204, 2301, 2303, 2305, 2402, 2404],
            dtype='int64', name='ID'),
 '奇数行': Int64Index([1101, 1103, 1105, 1202, 1204, 1301, 1303, 1305, 2102, 2104, 2201,
             2203, 2205, 2302, 2304, 2401, 2403, 2405],
            dtype='int64', name='ID')}
# 此处只是演示groupby的用法,实际操作不会这样写
math_score = df.set_index(['Gender', 'School'])['Math'].sort_index()
grouped_score = df.set_index(['Gender', 'School']) \
.sort_index().groupby(lambda x: (x, '均分及格' \
                                 if math_score[x].mean() >= 60 else '均分不及格'))
for name, group in grouped_score:
    print(name)
(('F', 'S_1'), '均分及格')
(('F', 'S_2'), '均分及格')
(('M', 'S_1'), '均分及格')
(('M', 'S_2'), '均分不及格')

4.2.4 groupby()的[]操作

print(df.groupby(['Gender','School'])['Math'].mean() >= 60)
Gender  School
F       S_1        True
        S_2        True
M       S_1        True
        S_2       False
Name: Math, dtype: bool
print(df.groupby(['Gender','School'])[['Math','Height']].mean())
                    Math      Height
Gender School                       
F      S_1     64.100000  173.125000
       S_2     66.427273  173.727273
M      S_1     63.342857  178.714286
       S_2     51.155556  172.000000

4.2.5 用groupby()对连续型变量进行分组

bins = [0, 40, 60, 80, 90, 100]
cuts = pd.cut(df['Math'], bins = bins)
df.groupby(cuts).size()
Math
(0, 40]       7
(40, 60]     10
(60, 80]      9
(80, 90]      7
(90, 100]     2
dtype: int64

5. groupby()的小伙伴们:agg(), filter(), transform()和apply()方法

5.1 聚合方法agg()

所谓聚合就是把一堆数,变成一个标量。因此,mean/sum/size/count/std/var/sem/describe/first/last/nth/min/max都是聚合函数。
实际上,计算各个统计量的过程就是一种聚合。

5.1.1 同时使用多个聚合函数

group_m = grouped_single['Math']
print(group_m.agg(['sum', 'mean', 'std']))
           sum       mean        std
School                              
S_1      956.2  63.746667  23.077474
S_2     1191.1  59.555000  17.589305

5.1.2 对聚合结果的列重命名

print(group_m.agg([('rename_sum', 'sum'), ('rename_mean', 'mean')]))
        rename_sum  rename_mean
School                         
S_1          956.2    63.746667
S_2         1191.1    59.555000

5.1.3 指定哪些列做哪种聚合

print(grouped_mul.agg({'Math':['mean', 'max'], 'Height':'var'}))
               Math       Height
               mean   max    var
School Class                    
S_1    C_1    63.78  87.2  183.3
       C_2    64.30  97.0  132.8
       C_3    63.16  87.7  179.2
S_2    C_1    58.56  83.3   54.7
       C_2    62.80  85.4  256.0
       C_3    63.06  95.5  205.7
       C_4    53.80  67.7  300.2

5.1.4 自定义聚合函数

agg()方法参数的传入是分组逐列进行的。有了这个特性就可以做许多事情。

grouped_single['Math'].agg(lambda x: print(x.head(), '间隔'))
1101    34.0
1102    32.5
1103    87.2
1104    80.4
1105    84.8
Name: Math, dtype: float64 间隔
2101    83.3
2102    50.6
2103    52.5
2104    72.2
2105    34.2
Name: Math, dtype: float64 间隔
School
S_1    None
S_2    None
Name: Math, dtype: object
print(grouped_single['Math'].agg(lambda x: x.max() - x.min()))
School
S_1    65.5
S_2    62.8
Name: Math, dtype: float64
def R1(x):
    return x.max() - x.min()
def R2(x):
    return x.max() - x.median()

print(grouped_single['Math'].agg(min_score1 = pd.NamedAgg(column = 'col1', \
                                                          aggfunc = R1),
                                 max_score1 = pd.NamedAgg(column = 'col2', \
                                                          aggfunc ='max'),
                                 range_score2 = pd.NamedAgg(column = 'col3', \
                                                            aggfunc = R2)).head())
        min_score1  max_score1  range_score2
School                                      
S_1           65.5        97.0          33.5
S_2           62.8        95.5          39.4
def f(s, low, high):
    return s.between(low, high).max()

print(grouped_single['Math'].agg(f, 50, 52))
School
S_1    False
S_2     True
Name: Math, dtype: bool
def f_test(s, low, high):
    return s.between(low, high).max()
def agg_f(f_mul,name, *args, **kwargs):
    def wrapper(x):
        return f_mul(x, *args, **kwargs)
    wrapper.__name__ = name
    return wrapper

new_f = agg_f(f_test, 'at_least_one_in_50_52', 50, 52)
print(grouped_single['Math'].agg([new_f, 'mean']).head())
        at_least_one_in_50_52       mean
School                                  
S_1                     False  63.746667
S_2                      True  59.555000

5.2 过滤方法filter()

filter()方法是用来筛选某些组的(务必记住结果是组的全体),因此传入的值应当是布尔标量。

print(grouped_single[['Math','Physics']].filter(lambda x: \
                                                (x['Math'] > 32).all()).head())
      Math Physics
ID                
2101  83.3       C
2102  50.6      B+
2103  52.5      B-
2104  72.2      B+
2105  34.2       A

5.3 变换方法transform()

5.3.1 传入参数

transform()方法传入的参数是组内的列,并且返回值需要与列长完全一致。如果返回了标量值,那么组内的所有元素会被广播为这个值。

print(grouped_single[['Math', 'Height']].head())
print(grouped_single[['Math', 'Height']].transform(lambda x: x - x.min()).head())
      Math  Height
ID                
1101  34.0     173
1102  32.5     192
1103  87.2     186
1104  80.4     167
1105  84.8     159
2101  83.3     174
2102  50.6     161
2103  52.5     157
2104  72.2     159
2105  34.2     170
      Math  Height
ID                
1101   2.5      14
1102   1.0      33
1103  55.7      27
1104  48.9       8
1105  53.3       0
print(grouped_single[['Math', 'Height']].transform(lambda x: x.mean()).head())
           Math      Height
ID                         
1101  63.746667  175.733333
1102  63.746667  175.733333
1103  63.746667  175.733333
1104  63.746667  175.733333
1105  63.746667  175.733333

5.3.2 利用变换进行组内标准化

print(grouped_single[['Math','Height']].transform(lambda x: \
                                                  (x - x.mean()) / x.std()).head())
          Math    Height
ID                      
1101 -1.288991 -0.214991
1102 -1.353990  1.279460
1103  1.016287  0.807528
1104  0.721627 -0.686923
1105  0.912289 -1.316166

5.3.3 利用变换进行组内缺失值处理

df_nan = df[['Math','School']].copy().reset_index()
df_nan.loc[np.random.randint(0, df.shape[0], 25),['Math']] = np.nan
print(df_nan.head())
     ID  Math School
0  1101  34.0    S_1
1  1102  32.5    S_1
2  1103   NaN    S_1
3  1104   NaN    S_1
4  1105  84.8    S_1
print(df_nan.groupby('School'). \
      transform(lambda x: x.fillna(x.mean())).join(df.reset_index()['School']).head())
     ID  Math School
0  1101  34.0    S_1
1  1102  32.5    S_1
2  1103  60.0    S_1
3  1104  60.0    S_1
4  1105  84.8    S_1

5.4 应用方法apply()

5.4.1 apply()方法的灵活性

apply()方法应该是最常见的分组方法,这都要得益于它的灵活性。apply函数的灵活性很大程度来源于其返回值的多样性。对于传入值而言,它是以分组后的表传入的(注意不是列,而是表)。

df.groupby('School').apply(lambda x: print(x.head(1)))
     School Class Gender   Address  Height  Weight  Math Physics
ID                                                              
1101    S_1   C_1      M  street_1     173      63  34.0      A+
     School Class Gender   Address  Height  Weight  Math Physics
ID                                                              
2101    S_2   C_1      M  street_7     174      84  83.3       C
print(df[['School', 'Math', 'Height']].groupby('School').apply(lambda x: x.max()))
       School  Math  Height
School                     
S_1       S_1  97.0     195
S_2       S_2  95.5     194
print(df[['School', 'Math', 'Height']]. \
      groupby('School').apply(lambda x: x - x.min()).head())
      Math  Height
ID                
1101   2.5    14.0
1102   1.0    33.0
1103  55.7    27.0
1104  48.9     8.0
1105  53.3     0.0
print(df[['School','Math','Height']].groupby('School')\
    .apply(lambda x:pd.DataFrame({'col1':x['Math']-x['Math'].max(),
                                  'col2':x['Math']-x['Math'].min(),
                                  'col3':x['Height']-x['Height'].max(),
                                  'col4':x['Height']-x['Height'].min()})).head())
      col1  col2  col3  col4
ID                          
1101 -63.0   2.5   -22    14
1102 -64.5   1.0    -3    33
1103  -9.8  55.7    -9    27
1104 -16.6  48.9   -28     8
1105 -12.2  53.3   -36     0

5.4.2 用apply()方法同时统计多个统计量

此处可以借助OrderedDict工具进行快捷的统计。

from collections import OrderedDict
def f(df):
    data = OrderedDict()
    data['M_sum'] = df['Math'].sum()
    data['W_var'] = df['Weight'].var()
    data['H_mean'] = df['Height'].mean()
    return pd.Series(data)
print(grouped_single.apply(f))
         M_sum       W_var      H_mean
School                                
S_1      956.2  117.428571  175.733333
S_2     1191.1  181.081579  172.950000

6. 问题与练习

6.1 问题

【问题一】 什么是fillna的前向/后向填充,如何实现?

答案见[1]
【问题二】 下面的代码实现了什么功能?请仿照设计一个它的groupby版本。

s = pd.Series ([0, 1, 1, 0, 1, 1, 1, 0])
s1 = s.cumsum()
result = s.mul(s1).diff().where(lambda x: x < 0).ffill().add(s1,fill_value = 0)
print(result)
0    0.0
1    1.0
2    2.0
3    0.0
4    1.0
5    2.0
6    3.0
7    0.0
dtype: float64

实现了对累计连续为1的数量的统计。

s1 = (-s+1).cumsum()
result = s.groupby(s1).cumsum()
result

【问题三】 如何计算组内0.25分位数与0.75分位数?要求显示在同一张表上。

def R1(x):
    return np.percentile(x, 25)
def R2(x):
    return np.percentile(x, 75)

print(grouped_single.agg(percent_25 = pd.NamedAgg(column = 'Math', aggfunc = R1),
                         percent_75 = pd.NamedAgg(column = 'Math', aggfunc = R2)))

【问题四】 既然索引已经能够选出某些符合条件的子集,那么filter函数的设计有什么意义?

filter()方法可以筛选满足条件的组,而符合条件的数据未必是同一组的。
【问题五】 整合、变换、过滤三者在输入输出和功能上有何异同?

聚合输入每一个组的多个列并对每个列做不同的聚合操作,输出多是一个标量;

变换输入每一个组的多个列并对每个列做同一个变换操作,输出是一个与输入的组等长的序列或者表格;

过滤输入由每一个组的多个列得到的布尔函数(变量),输出一个与输入的组等长的布尔序列。
【问题六】 在带参数的多函数聚合时,有办法能够绕过wrap技巧实现同样功能吗?

改写多参数函数为单参数函数,将原参数设置为全局变量。

6.2 练习

略。

7. 参考文献

1. http://www.voidcn.com/article/p-qagwmjov-buv.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值