pandas教程:Data Aggregation 数据聚合-灵析社区

清晨我上码

10.2 Data Aggregation(数据聚合)

聚合(Aggregation)指的是一些数据转化(data transformation),这些数据转化能从数组中产生标量(scalar values)。下面的例子就是一些聚合方法,包括mean, count, min and sum。我们可能会好奇,在一个GroupBy对象上调用mean()的时候,究竟发生了什么。一些常见的聚合,比如下表,实现方法上都已经被优化过了。当然,我们可以使用的聚合方法不止这些:

我们可以使用自己设计的聚合方法,而且可以调用分组后对象上的任意方法。例如,我们可以调用quantile来计算Series或DataFrame中列的样本的百分数。

尽管quantile并不是专门为GroupBy对象设计的方法,这是一个Series方法,但仍可以被GroupBy对象使用。GroupBy会对Series进行切片(slice up),并对于切片后的每一部分调用piece.quantile(0.9),然后把每部分的结果整合到一起:

import numpy as np
import pandas as pd
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)})
df

grouped = df.groupby('key1')
for key, group in grouped:
    print(key)
    print(group)
a
      data1     data2 key1 key2
0  1.707738  0.186729    a  one
1  1.069831  1.305796    a  two
4  0.341176  0.429461    a  one
b
      data1     data2 key1 key2
2 -2.291339 -1.609071    b  one
3  1.348090 -0.294999    b  two
grouped['data1'].quantile(0.9)
key1
a    1.580157
b    0.984147
Name: data1, dtype: float64

如果想用自己设计的聚合函数,把用于聚合数组的函数传入到aggregate或agg方法即可:

def peak_to_peak(arr):
    return arr.max() - arr.min()
grouped.agg(peak_to_peak)

我们发现很多方法,比如describe,也能正常使用,尽管严格的来说,这并不是聚合:

grouped.describe()

细节的部分在10.3会进行更多解释。

注意:自定义的函数会比上面表中的函数慢一些,上面的函数时优化过的,而自定义的函数会有一些额外的计算,所以慢一些。

1 Column-Wise and Multiple Function Application(列对列和多函数应用)

让我们回到tipping数据集。加载数据及后,我们添加一列用于描述小费的百分比:

tips = pd.read_csv('../examples/tips.csv')
# Add tip percentage of total bill
tips['tip_pct'] = tips['tip'] / tips['total_bill']
tips[:6]

我们可以看到,对series或DataFrame进行聚合,其实就是通过aggregate使用合适的函数,或者调用一些像mean或std这样的方法。然而,我们可能想要在列上使用不同的函数进行聚合,又或者想要一次执行多个函数。幸运的是,这是可能的,下面将通过一些例子来说明。首先,对于tips数据集,先用day和smoker进行分组:

grouped = tips.groupby(['day', 'smoker'])

对于像是上面表格10-1中的一些描述性统计,我们可以直接传入函数的名字,即字符串:

grouped_pct = grouped['tip_pct']
for name, group in grouped_pct:
    print(name)
    print(group[:2], '\n')


('Fri', 'No')
91    0.155625
94    0.142857
Name: tip_pct, dtype: float64 

('Fri', 'Yes')
90    0.103555
92    0.173913
Name: tip_pct, dtype: float64 

('Sat', 'No')
19    0.162228
20    0.227679
Name: tip_pct, dtype: float64 

('Sat', 'Yes')
56    0.078927
58    0.156584
Name: tip_pct, dtype: float64 

('Sun', 'No')
0    0.059447
1    0.160542
Name: tip_pct, dtype: float64 

('Sun', 'Yes')
164    0.171331
172    0.710345
Name: tip_pct, dtype: float64 

('Thur', 'No')
77    0.147059
78    0.131810
Name: tip_pct, dtype: float64 

('Thur', 'Yes')
80    0.154321
83    0.152999
Name: tip_pct, dtype: float64 
grouped_pct.agg('mean')
day   smoker
Fri   No        0.151650
      Yes       0.174783
Sat   No        0.158048
      Yes       0.147906
Sun   No        0.160113
      Yes       0.187250
Thur  No        0.160298
      Yes       0.163863
Name: tip_pct, dtype: float64

如果我们把函数或函数的名字作为一个list传入,我们会得到一个DataFrame,每列的名字就是函数的名字:

# def peak_to_peak(arr):
#     return arr.max() - arr.min()
grouped_pct.agg(['mean', 'std', peak_to_peak])

上面我们把多个聚合函数作为一个list传入给agg,这些函数会独立对每一个组进行计算。

上面结果的列名是自动给出的,当然,我们也可以更改这些列名。这种情况下,传入一个由tuple组成的list,每个tuple的格式是(name, function),每个元组的第一个元素会被用于作为DataFrame的列名(我们可以认为这个二元元组list是一个有序的映射):

grouped_pct.agg([('foo', 'mean'), ('bar', np.std)])

如果是处理一个DataFrame,我们有更多的选择,我们可以用一个含有多个函数的list应用到所有的列上,也可以在不同的列上应用不同的函数。演示一下,假设我们想要在tip_pct和total_bill这两列上,计算三个相同的统计指标:

functions = ['count', 'mean', 'max']
result = grouped['tip_pct', 'total_bill'].agg(functions)
result

我们可以看到,结果中的DataFrame有多层级的列(hierarchical columns)。另外一种做法有相同的效果,即我们对于每一列单独进行聚合(aggregating each column separately),然后使用concat把结果都结合在一起,然后用列名作为keys参数:

result['tip_pct']

我们之前提到过,可以用元组组成的list来自己定义列名:

ftuples = [('Durchschnitt', 'mean'), ('Abweichung', np.var)]
grouped['tip_pct', 'total_bill'].agg(ftuples)

现在,假设我们想要把不同的函数用到一列或多列上。要做到这一点,给agg传递一个dict,这个dict需要包含映射关系,用来表示列名和函数之间的对应关系:

grouped.agg({'tip': np.max, 'size': 'sum'})

grouped.agg({'tip_pct': ['min', 'max', 'mean', 'std'],
             'size': 'sum'})

只有当多个函数用于至少一列的时候,DataFrame才会有多层级列(hierarchical columns)

2 Returning Aggregated Data Without Row Indexes(不使用行索引返回聚合数据)

目前为止提到的所有例子,最后返回的聚合数据都是有索引的,而且这个索引默认是多层级索引,这个索引是由不同的组键的组合构成的(unique group key combinations)。因为我们并不是总需要返回这种索引,所以我们可以取消这种模式,在调用groupby的时候设定as_index=False即可:

tips.groupby(['day', 'smoker'], as_index=False).mean()

当然,我们也可以在上面的结果上直接调用reset_index,这样的话就能得到之前那种多层级索引的结果。不过使用as_index=False方法可以避免一些不必要的计算。

阅读量:72

点赞量:0

收藏量:0