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
def top(df, n=5, column='tip_pct'):
return df.sort_values(by=column)[-n:]
top(tips, n=6)
total_bill tip smoker day time size tip_pct
109 14.31 4.00 Yes Sat Dinner 2 0.279525
183 23.17 6.50 Yes Sun Dinner 4 0.280535
232 11.61 3.39 No Sat Dinner 2 0.291990
67 3.07 1.00 Yes Sat Dinner 1 0.325733
178 9.60 4.00 Yes Sun Dinner 2 0.416667
172 7.25 5.15 Yes Sun Dinner 2 0.710345
tip_pct 기준으로 정렬을 한 후, 가장 큰 6개의 열에 대해서 가져왔습니다.
이를 이용하여 apply 함수를 적용할 수 있습니다.
tips.groupby('smoker').apply(top)
total_bill tip smoker day time size tip_pct
smoker
No 88 24.71 5.85 No Thur Lunch 2 0.236746
185 20.69 5.00 No Sun Dinner 5 0.241663
51 10.29 2.60 No Sun Dinner 2 0.252672
149 7.51 2.00 No Thur Lunch 2 0.266312
232 11.61 3.39 No Sat Dinner 2 0.291990
Yes 109 14.31 4.00 Yes Sat Dinner 2 0.279525
183 23.17 6.50 Yes Sun Dinner 4 0.280535
67 3.07 1.00 Yes Sat Dinner 1 0.325733
178 9.60 4.00 Yes Sun Dinner 2 0.416667
172 7.25 5.15 Yes Sun Dinner 2 0.710345
우선 df를 smoker를 기준으로 그룹화 했고, 위의 top 함수를 적용했습니다.
이때 smoker 인덱스에 따라 각각 다섯 개씩 가져왔습니다.
tips.groupby(['smoker', 'day']).apply(top, n=1, column='total_bill')
total_bill tip smoker day time size tip_pct
smoker day
No Fri 94 22.75 3.25 No Fri Dinner 2 0.142857
Sat 212 48.33 9.00 No Sat Dinner 4 0.186220
Sun 156 48.17 5.00 No Sun Dinner 6 0.103799
Thur 142 41.19 5.00 No Thur Lunch 5 0.121389
Yes Fri 95 40.17 4.73 Yes Fri Dinner 4 0.117750
Sat 170 50.81 10.00 Yes Sat Dinner 3 0.196812
Sun 182 45.35 3.50 Yes Sun Dinner 3 0.077178
Thur 197 43.11 5.00 Yes Thur Lunch 4 0.115982
이번에는 smoker, day를 기준으로 그룹화, top 함수에 파라미터를 넣어서 가져왔습니다.
이때 n = 1이라는 것은 smoker 인덱스 안의 day 인덱스에 해당하는 개수입니다.
smoker 인덱스를 하나씩 가져왔고, 그 안에 있는 day 인덱스를 각각 하나씩 가져왔습니다.
result = tips.groupby('smoker')['tip_pct'].describe()
result
count mean std min 25% 50% 75% max
smoker
No 151.0 0.159328 0.039910 0.056797 0.136906 0.155625 0.185014 0.291990
Yes 93.0 0.163196 0.085119 0.035638 0.106771 0.153846 0.195059 0.710345
result.unstack('smoker')
smoker
count No 151.000000
Yes 93.000000
mean No 0.159328
Yes 0.163196
std No 0.039910
Yes 0.085119
min No 0.056797
Yes 0.035638
25% No 0.136906
Yes 0.106771
50% No 0.155625
Yes 0.153846
75% No 0.185014
Yes 0.195059
max No 0.291990
Yes 0.710345
dtype: float64
이때 result를 smoker를 기준으로 unstack한 결과입니다.
Suppressing the Group Keys
tips.groupby('smoker', group_keys=False).apply(top)
total_bill tip smoker day time size tip_pct
88 24.71 5.85 No Thur Lunch 2 0.236746
185 20.69 5.00 No Sun Dinner 5 0.241663
51 10.29 2.60 No Sun Dinner 2 0.252672
149 7.51 2.00 No Thur Lunch 2 0.266312
232 11.61 3.39 No Sat Dinner 2 0.291990
109 14.31 4.00 Yes Sat Dinner 2 0.279525
183 23.17 6.50 Yes Sun Dinner 4 0.280535
67 3.07 1.00 Yes Sat Dinner 1 0.325733
178 9.60 4.00 Yes Sun Dinner 2 0.416667
172 7.25 5.15 Yes Sun Dinner 2 0.710345
smoker를 기준으로 그룹화 했지만, group key = False로 함으로써, 인덱스에 나타지 않게 되었습니다.
즉 원본 데이터를 유지하며, 그룹화했습니다.
Quantile and Bucket Analysis
frame = pd.DataFrame({'data1': np.random.randn(1000),
'data2': np.random.randn(1000)})
quartiles = pd.cut(frame.data1, 4)
quartiles[:10]
0 (-1.23, 0.489]
1 (-2.956, -1.23]
2 (-1.23, 0.489]
3 (0.489, 2.208]
4 (-1.23, 0.489]
5 (0.489, 2.208]
6 (-1.23, 0.489]
7 (-1.23, 0.489]
8 (0.489, 2.208]
9 (0.489, 2.208]
Name: data1, dtype: category
Categories (4, interval[float64, right]): [(-2.956, -1.23] < (-1.23, 0.489] < (0.489, 2.208] < (2.208, 3.928]]
데이터를 생성 후, 4개로 쪼갰습니다.
def get_stats(group):
return {'min': group.min(), 'max': group.max(),
'count': group.count(), 'mean': group.mean()}
grouped = frame.data2.groupby(quartiles)
grouped.apply(get_stats).unstack()
min max count mean
data1
(-2.956, -1.23] -3.399312 1.670835 95.0 -0.039521
(-1.23, 0.489] -2.989741 3.260383 598.0 -0.002051
(0.489, 2.208] -3.745356 2.954439 297.0 0.081822
(2.208, 3.928] -1.929776 1.765640 10.0 0.024750
grouped는 범위에 따라 나눠진 quartiles를 대상으로 다시 data2를 그룹화한 df입니다.
이후 get_stats 함수를 통해 적용한 결과입니다. 각각의 그룹에 함수를 적용하는 모습입니다.
만약 unstack()하지 않았다면, 계층적 인덱싱의 결과로 나왔을 것입니다.
또 다른 예시입니다.
이번엔 qcut을 한 모습입니다.
# Return quantile numbers
grouping = pd.qcut(frame.data1, 10, labels=False)
grouped = frame.data2.groupby(grouping)
grouped.apply(get_stats).unstack()
min max count mean
data1
0 -3.399312 1.670835 100.0 -0.049902
1 -1.950098 2.628441 100.0 0.030989
2 -2.925113 2.527939 100.0 -0.067179
3 -2.315555 3.260383 100.0 0.065713
4 -2.047939 2.074345 100.0 -0.111653
5 -2.989741 2.184810 100.0 0.052130
6 -2.223506 2.458842 100.0 -0.021489
7 -3.056990 2.954439 100.0 -0.026459
8 -3.745356 2.735527 100.0 0.103406
9 -2.064111 2.377020 100.0 0.220122