0
点赞
收藏
分享

微信扫一扫

开启创造力之门:掌握Vue中Slot插槽的使用技巧与灵感

非宁静不致远 2023-11-16 阅读 36

文章目录

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

data1data2key1key2
01.7077380.186729aone
11.0698311.305796atwo
2-2.291339-1.609071bone
31.348090-0.294999btwo
40.3411760.429461aone

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)

data1data2
key1
a1.3665631.119067
b3.6394301.314072

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

grouped.describe()

data1data2
key1
acount3.0000003.000000
mean1.0395820.640662
std0.6837830.588670
min0.3411760.186729
25%0.7055030.308095
50%1.0698310.429461
75%1.3887850.867629
max1.7077381.305796
bcount2.0000002.000000
mean-0.471624-0.952035
std2.5734650.929189
min-2.291339-1.609071
25%-1.381482-1.280553
50%-0.471624-0.952035
75%0.438233-0.623517
max1.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_billtipsmokerdaytimesizetip_pct
016.991.01NoSunDinner20.059447
110.341.66NoSunDinner30.160542
221.013.50NoSunDinner30.166587
323.683.31NoSunDinner20.139780
424.593.61NoSunDinner40.146808
525.294.71NoSunDinner40.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])

meanstdpeak_to_peak
daysmoker
FriNo0.1516500.0281230.067349
Yes0.1747830.0512930.159925
SatNo0.1580480.0397670.235193
Yes0.1479060.0613750.290095
SunNo0.1601130.0423470.193226
Yes0.1872500.1541340.644685
ThurNo0.1602980.0387740.193350
Yes0.1638630.0393890.151240

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

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

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

foobar
daysmoker
FriNo0.1516500.028123
Yes0.1747830.051293
SatNo0.1580480.039767
Yes0.1479060.061375
SunNo0.1601130.042347
Yes0.1872500.154134
ThurNo0.1602980.038774
Yes0.1638630.039389

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

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

tip_pcttotal_bill
countmeanmaxcountmeanmax
daysmoker
FriNo40.1516500.187735418.42000022.75
Yes150.1747830.2634801516.81333340.17
SatNo450.1580480.2919904519.66177848.33
Yes420.1479060.3257334221.27666750.81
SunNo570.1601130.2526725720.50666748.17
Yes190.1872500.7103451924.12000045.35
ThurNo450.1602980.2663124517.11311141.19
Yes170.1638630.2412551719.19058843.11

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

result['tip_pct']

countmeanmax
daysmoker
FriNo40.1516500.187735
Yes150.1747830.263480
SatNo450.1580480.291990
Yes420.1479060.325733
SunNo570.1601130.252672
Yes190.1872500.710345
ThurNo450.1602980.266312
Yes170.1638630.241255

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

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

tip_pcttotal_bill
DurchschnittAbweichungDurchschnittAbweichung
daysmoker
FriNo0.1516500.00079118.42000025.596333
Yes0.1747830.00263116.81333382.562438
SatNo0.1580480.00158119.66177879.908965
Yes0.1479060.00376721.276667101.387535
SunNo0.1601130.00179320.50666766.099980
Yes0.1872500.02375724.120000109.046044
ThurNo0.1602980.00150317.11311159.625081
Yes0.1638630.00155119.19058869.808518

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

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

tipsize
daysmoker
FriNo3.509
Yes4.7331
SatNo9.00115
Yes10.00104
SunNo6.00167
Yes6.5049
ThurNo6.70112
Yes5.0040

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

tip_pctsize
minmaxmeanstdsum
daysmoker
FriNo0.1203850.1877350.1516500.0281239
Yes0.1035550.2634800.1747830.05129331
SatNo0.0567970.2919900.1580480.039767115
Yes0.0356380.3257330.1479060.061375104
SunNo0.0594470.2526720.1601130.042347167
Yes0.0656600.7103450.1872500.15413449
ThurNo0.0729610.2663120.1602980.038774112
Yes0.0900140.2412550.1638630.03938940

只有当多个函数用于至少一列的时候,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()

daysmokertotal_billtipsizetip_pct
0FriNo18.4200002.8125002.2500000.151650
1FriYes16.8133332.7140002.0666670.174783
2SatNo19.6617783.1028892.5555560.158048
3SatYes21.2766672.8754762.4761900.147906
4SunNo20.5066673.1678952.9298250.160113
5SunYes24.1200003.5168422.5789470.187250
6ThurNo17.1131112.6737782.4888890.160298
7ThurYes19.1905883.0300002.3529410.163863

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

举报

相关推荐

0 条评论