pandas教程:Data Aggregation 数据聚合

文章目录

  • 10.2 Data Aggregation(数据聚合)
  • 1 Column-Wise and Multiple Function Application(列对列和多函数应用)
  • 2 Returning Aggregated Data Without Row Indexes(不使用行索引返回聚合数据)

10.2 Data Aggregation(数据聚合)

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

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

尽管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
data1 data2 key1 key2
0 1.707738 0.186729 a one
1 1.069831 1.305796 a two
2 -2.291339 -1.609071 b one
3 1.348090 -0.294999 b two
4 0.341176 0.429461 a one
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

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

def peak_to_peak(arr):
    return arr.max() - arr.min()
grouped.agg(peak_to_peak)
data1 data2
key1
a 1.366563 1.119067
b 3.639430 1.314072

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

grouped.describe()
data1 data2
key1
a count 3.000000 3.000000
mean 1.039582 0.640662
std 0.683783 0.588670
min 0.341176 0.186729
25% 0.705503 0.308095
50% 1.069831 0.429461
75% 1.388785 0.867629
max 1.707738 1.305796
b count 2.000000 2.000000
mean -0.471624 -0.952035
std 2.573465 0.929189
min -2.291339 -1.609071
25% -1.381482 -1.280553
50% -0.471624 -0.952035
75% 0.438233 -0.623517
max 1.348090 -0.294999

细节的部分在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]
total_bill tip smoker day time size tip_pct
0 16.99 1.01 No Sun Dinner 2 0.059447
1 10.34 1.66 No Sun Dinner 3 0.160542
2 21.01 3.50 No Sun Dinner 3 0.166587
3 23.68 3.31 No Sun Dinner 2 0.139780
4 24.59 3.61 No Sun Dinner 4 0.146808
5 25.29 4.71 No Sun Dinner 4 0.186240

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

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])
mean std peak_to_peak
day smoker
Fri No 0.151650 0.028123 0.067349
Yes 0.174783 0.051293 0.159925
Sat No 0.158048 0.039767 0.235193
Yes 0.147906 0.061375 0.290095
Sun No 0.160113 0.042347 0.193226
Yes 0.187250 0.154134 0.644685
Thur No 0.160298 0.038774 0.193350
Yes 0.163863 0.039389 0.151240

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

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

grouped_pct.agg([('foo', 'mean'), ('bar', np.std)])
foo bar
day smoker
Fri No 0.151650 0.028123
Yes 0.174783 0.051293
Sat No 0.158048 0.039767
Yes 0.147906 0.061375
Sun No 0.160113 0.042347
Yes 0.187250 0.154134
Thur No 0.160298 0.038774
Yes 0.163863 0.039389

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

functions = ['count', 'mean', 'max']
result = grouped['tip_pct', 'total_bill'].agg(functions)
result
tip_pct total_bill
count mean max count mean max
day smoker
Fri No 4 0.151650 0.187735 4 18.420000 22.75
Yes 15 0.174783 0.263480 15 16.813333 40.17
Sat No 45 0.158048 0.291990 45 19.661778 48.33
Yes 42 0.147906 0.325733 42 21.276667 50.81
Sun No 57 0.160113 0.252672 57 20.506667 48.17
Yes 19 0.187250 0.710345 19 24.120000 45.35
Thur No 45 0.160298 0.266312 45 17.113111 41.19
Yes 17 0.163863 0.241255 17 19.190588 43.11

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

result['tip_pct']
count mean max
day smoker
Fri No 4 0.151650 0.187735
Yes 15 0.174783 0.263480
Sat No 45 0.158048 0.291990
Yes 42 0.147906 0.325733
Sun No 57 0.160113 0.252672
Yes 19 0.187250 0.710345
Thur No 45 0.160298 0.266312
Yes 17 0.163863 0.241255

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

ftuples = [('Durchschnitt', 'mean'), ('Abweichung', np.var)]
grouped['tip_pct', 'total_bill'].agg(ftuples)
tip_pct total_bill
Durchschnitt Abweichung Durchschnitt Abweichung
day smoker
Fri No 0.151650 0.000791 18.420000 25.596333
Yes 0.174783 0.002631 16.813333 82.562438
Sat No 0.158048 0.001581 19.661778 79.908965
Yes 0.147906 0.003767 21.276667 101.387535
Sun No 0.160113 0.001793 20.506667 66.099980
Yes 0.187250 0.023757 24.120000 109.046044
Thur No 0.160298 0.001503 17.113111 59.625081
Yes 0.163863 0.001551 19.190588 69.808518

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

grouped.agg({'tip': np.max, 'size': 'sum'})
tip size
day smoker
Fri No 3.50 9
Yes 4.73 31
Sat No 9.00 115
Yes 10.00 104
Sun No 6.00 167
Yes 6.50 49
Thur No 6.70 112
Yes 5.00 40
grouped.agg({'tip_pct': ['min', 'max', 'mean', 'std'],
             'size': 'sum'})
tip_pct size
min max mean std sum
day smoker
Fri No 0.120385 0.187735 0.151650 0.028123 9
Yes 0.103555 0.263480 0.174783 0.051293 31
Sat No 0.056797 0.291990 0.158048 0.039767 115
Yes 0.035638 0.325733 0.147906 0.061375 104
Sun No 0.059447 0.252672 0.160113 0.042347 167
Yes 0.065660 0.710345 0.187250 0.154134 49
Thur No 0.072961 0.266312 0.160298 0.038774 112
Yes 0.090014 0.241255 0.163863 0.039389 40

只有当多个函数用于至少一列的时候,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()
day smoker total_bill tip size tip_pct
0 Fri No 18.420000 2.812500 2.250000 0.151650
1 Fri Yes 16.813333 2.714000 2.066667 0.174783
2 Sat No 19.661778 3.102889 2.555556 0.158048
3 Sat Yes 21.276667 2.875476 2.476190 0.147906
4 Sun No 20.506667 3.167895 2.929825 0.160113
5 Sun Yes 24.120000 3.516842 2.578947 0.187250
6 Thur No 17.113111 2.673778 2.488889 0.160298
7 Thur Yes 19.190588 3.030000 2.352941 0.163863

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

你可能感兴趣的:(pandas使用教程,pandas,python,前端,numpy,LDA)