10장 데이터 집계와 그룹 연산¶
10.1 GroupBy 메카닉¶
import pandas as pd
import numpy as np
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
key1 | key2 | data1 | data2 | |
---|---|---|---|---|
0 | a | one | 0.566154 | 1.880500 |
1 | a | two | 0.427635 | -1.143182 |
2 | b | one | -1.269009 | 1.447449 |
3 | b | two | 0.745902 | -0.624200 |
4 | a | one | -2.069218 | -1.594180 |
이 데이터를 key1로 묶고 각 그룹에서 data1의 평균을 구해보자
방법 중 하나는 data1에 대해 groupby 메서드를 호출하고 key1 컬럼을 넘기는 것
grouped = df['data1'].groupby(df['key1'])
list(grouped)
[('a', 0 0.566154 1 0.427635 4 -2.069218 Name: data1, dtype: float64), ('b', 2 -1.269009 3 0.745902 Name: data1, dtype: float64)]
이 grouped 변수는 GroupBy 객체
그룹별 평균을 구하려면 GroupBy 객체의 mean 메서드 사용
grouped.mean()
key1 a -0.358476 b -0.261554 Name: data1, dtype: float64
데이터(Series 객체)는 그룹 색인에 따라 수집되고 key1 컬럼에 있는 유일한 값으로 색인되는 새로운 Series 객체가 생성됨
새롭게 생성된 Series 객체의 색인은 'key1'인데, 그 이유는 DataFrame 컬럼인 df['key1'] 때문
여러 개의 배열을 리스트로 넘기면 다른 결과가 나옴
means = df['data1'].groupby([df['key1'], df['key2']]).mean()
means
key1 key2 a one -0.751532 two 0.427635 b one -1.269009 two 0.745902 Name: data1, dtype: float64
여기서는 데이터를 두 개의 색인으로 묶었고, 그 결과 계층적 색인을 가지는 Series를 얻음
means.unstack() #인덱스를 컬럼으로
key2 | one | two |
---|---|---|
key1 | ||
a | -0.751532 | 0.427635 |
b | -1.269009 | 0.745902 |
이 예제에서는 그룹의 색인 모두 Series 객체인데, 길이만 같다면 어떤 배열이라도 상관 X
df
key1 | key2 | data1 | data2 | |
---|---|---|---|---|
0 | a | one | 0.566154 | 1.880500 |
1 | a | two | 0.427635 | -1.143182 |
2 | b | one | -1.269009 | 1.447449 |
3 | b | two | 0.745902 | -0.624200 |
4 | a | one | -2.069218 | -1.594180 |
df['data1']
0 0.566154 1 0.427635 2 -1.269009 3 0.745902 4 -2.069218 Name: data1, dtype: float64
states = np.array(['Ohio', 'California', 'California', 'Ohio', 'Ohio'])
states
array(['Ohio', 'California', 'California', 'Ohio', 'Ohio'], dtype='<U10')
years = np.array([2005, 2005, 2006, 2005, 2006])
years
array([2005, 2005, 2006, 2005, 2006])
df['data1'].groupby([states, years]).mean()
California 2005 0.427635 2006 -1.269009 Ohio 2005 0.656028 2006 -2.069218 Name: data1, dtype: float64
한 그룹으로 묶을 정보는 주로 같은 DataFrame 안에서 찾게 되는데,
이 경우 컬럼 이름(문자열, 숫자 혹은 다른 파이썬 객체)을 넘겨서 그룹의 색인으로 사용
df
key1 | key2 | data1 | data2 | |
---|---|---|---|---|
0 | a | one | 1.240239 | 0.880415 |
1 | a | two | 0.475952 | -0.109323 |
2 | b | one | -0.199968 | 1.681879 |
3 | b | two | 0.303913 | 0.144662 |
4 | a | one | 0.612815 | 1.143232 |
df.groupby('key1').mean()
C:\Users\ADMIN\AppData\Local\Temp\ipykernel_5000\2057825055.py:1: FutureWarning: The default value of numeric_only in DataFrameGroupBy.mean is deprecated. In a future version, numeric_only will default to False. Either specify numeric_only or select only columns which should be valid for the function. df.groupby('key1').mean()
data1 | data2 | |
---|---|---|
key1 | ||
a | 0.776336 | 0.638108 |
b | 0.051973 | 0.913271 |
df.groupby(['key1', 'key2']).mean()
data1 | data2 | ||
---|---|---|---|
key1 | key2 | ||
a | one | 0.926527 | 1.011824 |
two | 0.475952 | -0.109323 | |
b | one | -0.199968 | 1.681879 |
two | 0.303913 | 0.144662 |
*성가신 컬럼*(nuisance column)
df.groupby('key1').mean() 코드를 보면 key2 컬럼이 결과에서 빠짐.
그 이유는 df['key2']가 숫자 데이터가 아니기 때문 이런 데이터를 성가신 컬럼이라고 부르며 결과에서 제외시킴
size()¶
그룹의 크기를 담고 있는 Series를 반환하는 유용한 GroupBy 메서드
df
key1 | key2 | data1 | data2 | |
---|---|---|---|---|
0 | a | one | 1.240239 | 0.880415 |
1 | a | two | 0.475952 | -0.109323 |
2 | b | one | -0.199968 | 1.681879 |
3 | b | two | 0.303913 | 0.144662 |
4 | a | one | 0.612815 | 1.143232 |
df.groupby(['key1', 'key2']).size()
key1 key2 a one 2 two 1 b one 1 two 1 dtype: int64
그룹 색인에서 누락된 값은 결과에서 제외됨
10.1.1 그룹 간 순회하기(for문)¶
GroupBy 객체는 이터레이션을 지원
그룹 이름과 그에 따른 데이터 묶음을 튜플로 반환
df
key1 | key2 | data1 | data2 | |
---|---|---|---|---|
0 | a | one | 1.240239 | 0.880415 |
1 | a | two | 0.475952 | -0.109323 |
2 | b | one | -0.199968 | 1.681879 |
3 | b | two | 0.303913 | 0.144662 |
4 | a | one | 0.612815 | 1.143232 |
for name, group in df.groupby('key1'):
print(name) # a,b
print(group)
a key1 key2 data1 data2 0 a one 1.240239 0.880415 1 a two 0.475952 -0.109323 4 a one 0.612815 1.143232 b key1 key2 data1 data2 2 b one -0.199968 1.681879 3 b two 0.303913 0.144662
이처럼 색인이 여럿 존재하는 경우 튜플의 첫 번째 원소가 색인값
df
key1 | key2 | data1 | data2 | |
---|---|---|---|---|
0 | a | one | -0.613641 | -0.236394 |
1 | a | two | -0.614691 | -0.785642 |
2 | b | one | 0.691855 | 0.134026 |
3 | b | two | 0.966128 | -2.341542 |
4 | a | one | -1.358573 | 1.300152 |
for (k1, k2), group in df.groupby(['key1', 'key2']):
print((k1, k2))
print(group)
('a', 'one') key1 key2 data1 data2 0 a one -0.613641 -0.236394 4 a one -1.358573 1.300152 ('a', 'two') key1 key2 data1 data2 1 a two -0.614691 -0.785642 ('b', 'one') key1 key2 data1 data2 2 b one 0.691855 0.134026 ('b', 'two') key1 key2 data1 data2 3 b two 0.966128 -2.341542
그룹별 데이터를 사전형으로 바꿀 수 있음
pieces = dict(list(df.groupby('key1')))
pieces
{'a': key1 key2 data1 data2 0 a one -0.613641 -0.236394 1 a two -0.614691 -0.785642 4 a one -1.358573 1.300152, 'b': key1 key2 data1 data2 2 b one 0.691855 0.134026 3 b two 0.966128 -2.341542}
pieces['b']
key1 | key2 | data1 | data2 | |
---|---|---|---|---|
2 | b | one | 0.691855 | 0.134026 |
3 | b | two | 0.966128 | -2.341542 |
groupby 메서드는 기본적으로 axis=0에 대해 그룹을 만드는데, 다른 축으로 그룹 만들기도 가능
예를 들어 예제로 살펴본 df의 컬럼을 dtype에 따라 그룹으로 묶기 가능
df
key1 | key2 | data1 | data2 | |
---|---|---|---|---|
0 | a | one | 1.240239 | 0.880415 |
1 | a | two | 0.475952 | -0.109323 |
2 | b | one | -0.199968 | 1.681879 |
3 | b | two | 0.303913 | 0.144662 |
4 | a | one | 0.612815 | 1.143232 |
df.dtypes
key1 object key2 object data1 float64 data2 float64 dtype: object
grouped = df.groupby(df.dtypes, axis = 1)
list(grouped)
[(dtype('float64'), data1 data2 0 1.240239 0.880415 1 0.475952 -0.109323 2 -0.199968 1.681879 3 0.303913 0.144662 4 0.612815 1.143232), (dtype('O'), key1 key2 0 a one 1 a two 2 b one 3 b two 4 a one)]
그룹을 아래처럼 출력가능
for dtype, group in grouped:
print(dtype)
print(group)
float64 data1 data2 0 1.240239 0.880415 1 0.475952 -0.109323 2 -0.199968 1.681879 3 0.303913 0.144662 4 0.612815 1.143232 object key1 key2 0 a one 1 a two 2 b one 3 b two 4 a one
10.1.2 컬럼이나 컬럼의 일부만 선택¶
DataFrame에서 만든 GroupBy 객체를 컬럼 이름이나 컬럼 이름이 담긴 배열로 색인하면 수집을 위해 해당 컬럼 선택
df
key1 | key2 | data1 | data2 | |
---|---|---|---|---|
0 | a | one | 1.240239 | 0.880415 |
1 | a | two | 0.475952 | -0.109323 |
2 | b | one | -0.199968 | 1.681879 |
3 | b | two | 0.303913 | 0.144662 |
4 | a | one | 0.612815 | 1.143232 |
list(df.groupby('key1')['data1'])
[('a', 0 0.566154 1 0.427635 4 -2.069218 Name: data1, dtype: float64), ('b', 2 -1.269009 3 0.745902 Name: data1, dtype: float64)]
list(df.groupby('key1')[['data2']])
[('a', data2 0 1.880500 1 -1.143182 4 -1.594180), ('b', data2 2 1.447449 3 -0.624200)]
위 코드는 아래 코드에 대한 신택틱 슈거로 같은 결과 반환
df['data1'].groupby(df['key1'])
df[['data2']].groupby(df['key1'])
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000029535468C70>
특히 대용량 데이터를 다룰 경우 소수의 컬럼만 집계하고 싶을 때가 있는데,
예를 들어 위 데이터에서 data2 컬럼에 대해서만 평균을 구하고 결과를 DataFrame으로 받고 싶다면 아래처럼 작성
df.groupby(['key1', 'key2'])[['data2']].mean()
data2 | ||
---|---|---|
key1 | key2 | |
a | one | 0.531879 |
two | -0.785642 | |
b | one | 0.134026 |
two | -2.341542 |
색인으로 얻은 객체는 groupby 메서드에 리스트나 배열을 넘겼을 경우 DataFrameGroupBy 객체가 되고,
단일 값으로 하나의 컬럼 이름만 넘겼을 경우 SeriesGroupBy 객체가 됨
s_grouped = df.groupby(['key1', 'key2'])['data2']
list(s_grouped)
[(('a', 'one'), 0 1.88050 4 -1.59418 Name: data2, dtype: float64), (('a', 'two'), 1 -1.143182 Name: data2, dtype: float64), (('b', 'one'), 2 1.447449 Name: data2, dtype: float64), (('b', 'two'), 3 -0.6242 Name: data2, dtype: float64)]
s_grouped.mean()
key1 key2 a one 0.143160 two -1.143182 b one 1.447449 two -0.624200 Name: data2, dtype: float64
10.1.3 사전과 Series에서 그룹핑하기¶
그룹 정보는 배열이 아닌 형태로 존재하기도 함
people = pd.DataFrame(np.random.randn(5,5),
columns = ['a', 'b', 'c', 'd', 'e'],
index = ['Joe', 'Steve', 'Wes', 'Jim', 'Travis'])
people.iloc[2:3, [1,2]] = np.nan # nan 값 추가
people
a | b | c | d | e | |
---|---|---|---|---|---|
Joe | 0.188912 | 0.801612 | -0.232075 | -0.313700 | 1.665236 |
Steve | 0.545823 | 0.886245 | -2.040800 | -0.097326 | 0.841638 |
Wes | 0.217945 | NaN | NaN | -0.050911 | 0.255653 |
Jim | -1.643611 | 0.821653 | 0.767637 | 1.335287 | -0.696760 |
Travis | -0.567461 | -0.712253 | -0.047007 | -0.552320 | 0.379381 |
이제 각 컬럼을 나타낼 그룹 목록이 있고, 그룹별로 컬럼의 값을 모두 더한다고 해보자
mapping = {'a':'red', 'b':'red', 'c':'blue',
'd':'blue', 'e':'red', 'f':'orange'}
이 사전에서 groupby 메서드로 넘길 배열을 뽑아낼 수 있지만 그냥 이 사전을 groupby 메서드로 넘기자
(사용하지 않는 그룹 키도 문제없다는 것을 보이기 위해 'f'도 포함시킴)
by_column = people.groupby(mapping, axis = 1)
list(by_column)
[('blue', c d Joe -0.232075 -0.313700 Steve -2.040800 -0.097326 Wes NaN -0.050911 Jim 0.767637 1.335287 Travis -0.047007 -0.552320), ('red', a b e Joe 0.188912 0.801612 1.665236 Steve 0.545823 0.886245 0.841638 Wes 0.217945 NaN 0.255653 Jim -1.643611 0.821653 -0.696760 Travis -0.567461 -0.712253 0.379381)]
by_column.sum()
blue | red | |
---|---|---|
Joe | -0.545775 | 2.655760 |
Steve | -2.138127 | 2.273706 |
Wes | -0.050911 | 0.473598 |
Jim | 2.102924 | -1.518718 |
Travis | -0.599327 | -0.900334 |
Series에 대해서도 같은 기능을 수행할 수 있는데, 고정된 크기의 맵이라고 보면 됨
map_series = pd.Series(mapping)
map_series
a red b red c blue d blue e red f orange dtype: object
people
a | b | c | d | e | |
---|---|---|---|---|---|
Joe | 0.188912 | 0.801612 | -0.232075 | -0.313700 | 1.665236 |
Steve | 0.545823 | 0.886245 | -2.040800 | -0.097326 | 0.841638 |
Wes | 0.217945 | NaN | NaN | -0.050911 | 0.255653 |
Jim | -1.643611 | 0.821653 | 0.767637 | 1.335287 | -0.696760 |
Travis | -0.567461 | -0.712253 | -0.047007 | -0.552320 | 0.379381 |
people.groupby(map_series, axis = 1).count() #Wes는 NaN 값이 두개라 1,2나옴
blue | red | |
---|---|---|
Joe | 2 | 3 |
Steve | 2 | 3 |
Wes | 1 | 2 |
Jim | 2 | 3 |
Travis | 2 | 3 |
10.1.4 함수로 그룹핑하기¶
people DataFrame은 사람의 이름을 색인값으로 사용
만약 이름의 길이별로 그룹을 묶고 싶다면 이름의 길이가 담긴 배열을 만들어 넘기는 대신 len 함수 넘기기
people
a | b | c | d | e | |
---|---|---|---|---|---|
Joe | 0.188912 | 0.801612 | -0.232075 | -0.313700 | 1.665236 |
Steve | 0.545823 | 0.886245 | -2.040800 | -0.097326 | 0.841638 |
Wes | 0.217945 | NaN | NaN | -0.050911 | 0.255653 |
Jim | -1.643611 | 0.821653 | 0.767637 | 1.335287 | -0.696760 |
Travis | -0.567461 | -0.712253 | -0.047007 | -0.552320 | 0.379381 |
people.groupby(len).sum()
a | b | c | d | e | |
---|---|---|---|---|---|
3 | -1.236754 | 1.623265 | 0.535562 | 0.970675 | 1.224129 |
5 | 0.545823 | 0.886245 | -2.040800 | -0.097326 | 0.841638 |
6 | -0.567461 | -0.712253 | -0.047007 | -0.552320 | 0.379381 |
내부적으로는 모두 배열로 변환되므로 함수를 배열, 사전 또는 Series와 섞어 쓰더라도 전혀 문제되지 X
key_list = ['one', 'one', 'one', 'two', 'two']
list(people.groupby([len, key_list]))
[((3, 'one'), a b c d e Joe 0.188912 0.801612 -0.232075 -0.313700 1.665236 Wes 0.217945 NaN NaN -0.050911 0.255653), ((3, 'two'), a b c d e Jim -1.643611 0.821653 0.767637 1.335287 -0.69676), ((5, 'one'), a b c d e Steve 0.545823 0.886245 -2.0408 -0.097326 0.841638), ((6, 'two'), a b c d e Travis -0.567461 -0.712253 -0.047007 -0.55232 0.379381)]
people.groupby([len, key_list]).min()
a | b | c | d | e | ||
---|---|---|---|---|---|---|
3 | one | 0.188912 | 0.801612 | -0.232075 | -0.313700 | 0.255653 |
two | -1.643611 | 0.821653 | 0.767637 | 1.335287 | -0.696760 | |
5 | one | 0.545823 | 0.886245 | -2.040800 | -0.097326 | 0.841638 |
6 | two | -0.567461 | -0.712253 | -0.047007 | -0.552320 | 0.379381 |
10.1.5 색인 단계로 그룹핑¶
계층적으로 색인된 데이터는 축 색인의 단계 중 하나를 사용해서 편리하게 집계할 수 있는 기능 제공
columns = pd.MultiIndex.from_arrays([['US', 'US', 'US', 'JP', 'JP'],
[1,3,5,1,3]],
names=['cty', 'tenor'])
hier_df = pd.DataFrame(np.random.randn(4,5), columns = columns)
hier_df
cty | US | JP | |||
---|---|---|---|---|---|
tenor | 1 | 3 | 5 | 1 | 3 |
0 | 0.821923 | 0.331688 | 2.390504 | -0.677578 | 0.492817 |
1 | 0.026397 | 0.519363 | -1.242051 | 1.284863 | -0.435164 |
2 | -0.439829 | -0.560173 | -1.394516 | 1.315166 | -0.399121 |
3 | -0.950598 | 0.545644 | -0.658576 | -1.116897 | -1.644269 |
level¶
이 기능을 사용하려면 level 예약어를 사용해 레벨 번호나 이름 넘기기
hier_df.groupby(level='cty', axis=1).count()
cty | JP | US |
---|---|---|
0 | 2 | 3 |
1 | 2 | 3 |
2 | 2 | 3 |
3 | 2 | 3 |
10.2 데이터 집계¶
데이터 집계는 배열로부터 스칼라값을 만들어내는 모든 데이터 변환 작업
최적화된 groupby메서드¶
함수 | 설명 |
---|---|
count | 그룹에서 NA가 아닌 값의 수를 반환 |
sum | NA가 아닌 값들의 합을 구함 |
mean | NA가 아닌 값들의 평균을 구함 |
quantile¶
quantile 메서드는 Series나 DataFrame의 변위치 계산
내부적으로 GroupBy는 Series를 효과적으로 잘게 자르고 각 조각에 대해 piece.quantile(0.9) 호출
그리고 이 결과들을 모두 하나의 객체로 합쳐서 반환
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
key1 | key2 | data1 | data2 | |
---|---|---|---|---|
0 | a | one | -0.561996 | 0.490998 |
1 | a | two | -0.149860 | 2.304877 |
2 | b | one | -0.538803 | -1.879414 |
3 | b | two | 0.083247 | -0.411135 |
4 | a | one | -1.801245 | -0.969078 |
grouped = df.groupby('key1')
grouped['data1'].quantile(0.9)
key1 a -0.232287 b 0.021042 Name: data1, dtype: float64
aggregate, agg¶
자신만의 데이터 집계함수를 사용하려면 배열의 aggregate나 agg 메서드에 해당 함수 넘기기
def peak_to_peak(arr):
return arr.max() - arr.min()
grouped.agg(peak_to_peak)
C:\Users\user\AppData\Local\Temp\ipykernel_14620\4193407341.py:1: FutureWarning: ['key2'] did not aggregate successfully. If any error is raised this will raise in a future version of pandas. Drop these columns/ops to avoid this warning. grouped.agg(peak_to_peak)
data1 | data2 | |
---|---|---|
key1 | ||
a | 1.651386 | 3.273955 |
b | 0.622050 | 1.468280 |
describe¶
describe 같은 메서드는 데이터를 집계하지 않는데도 잘 작동함
grouped.describe()
data1 | data2 | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
count | mean | std | min | 25% | 50% | 75% | max | count | mean | std | min | 25% | 50% | 75% | max | |
key1 | ||||||||||||||||
a | 3.0 | -0.837700 | 0.859522 | -1.801245 | -1.181621 | -0.561996 | -0.355928 | -0.149860 | 3.0 | 0.608932 | 1.640161 | -0.969078 | -0.239040 | 0.490998 | 1.397938 | 2.304877 |
b | 2.0 | -0.227778 | 0.439856 | -0.538803 | -0.383290 | -0.227778 | -0.072265 | 0.083247 | 2.0 | -1.145275 | 1.038231 | -1.879414 | -1.512345 | -1.145275 | -0.778205 | -0.411135 |
*NOTE_* 사용자 정의 집계함수는 일반적으로 groupby 메서드 함수에 비해 무척 느리게 작동,
그 이유는 중간 데이터를 생성하는 과정에서 함수 호출이나 데이터 정렬 같은 오버헤드가 발생하기 때문
10.2.1 컬럼에 여러 가지 함수 적용하기¶
팁 데이터로 다시 돌아가자.
여기서는 read_csv 함수로 데이터를 불러온 뒤 팁의 비율을 담기 위한 컬럼인 tip_pct 추가
tips = pd.read_csv('tips.csv')
tips
total_bill | tip | smoker | day | time | size | |
---|---|---|---|---|---|---|
0 | 16.99 | 1.01 | No | Sun | Dinner | 2 |
1 | 10.34 | 1.66 | No | Sun | Dinner | 3 |
2 | 21.01 | 3.50 | No | Sun | Dinner | 3 |
3 | 23.68 | 3.31 | No | Sun | Dinner | 2 |
4 | 24.59 | 3.61 | No | Sun | Dinner | 4 |
... | ... | ... | ... | ... | ... | ... |
239 | 29.03 | 5.92 | No | Sat | Dinner | 3 |
240 | 27.18 | 2.00 | Yes | Sat | Dinner | 2 |
241 | 22.67 | 2.00 | Yes | Sat | Dinner | 2 |
242 | 17.82 | 1.75 | No | Sat | Dinner | 2 |
243 | 18.78 | 3.00 | No | Thur | Dinner | 2 |
244 rows × 6 columns
#total_bill에서 tip의 비율을 추가
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 |
Sereis나 DataFrame의 모든 컬럼을 집계하기
- mean이나 std 같은 메서드 호출
- 원하는 함수에 aggregate 사용
컬럼에 따라 다른 함수를 사용해 집계를 수행하거나 여러 개의 함수를 한 번에 적용하기 원한다면 이를 쉽고 간단하게 수행 가능
먼저 tips를 day와 smoker별로 묶어보자
grouped = tips.groupby(['day', 'smoker'])
list(grouped)
[(('Fri', 'No'), total_bill tip smoker day time size tip_pct 91 22.49 3.50 No Fri Dinner 2 0.155625 94 22.75 3.25 No Fri Dinner 2 0.142857 99 12.46 1.50 No Fri Dinner 2 0.120385 223 15.98 3.00 No Fri Lunch 3 0.187735), (('Fri', 'Yes'), total_bill tip smoker day time size tip_pct 90 28.97 3.00 Yes Fri Dinner 2 0.103555 92 5.75 1.00 Yes Fri Dinner 2 0.173913 93 16.32 4.30 Yes Fri Dinner 2 0.263480 95 40.17 4.73 Yes Fri Dinner 4 0.117750 96 27.28 4.00 Yes Fri Dinner 2 0.146628 97 12.03 1.50 Yes Fri Dinner 2 0.124688 98 21.01 3.00 Yes Fri Dinner 2 0.142789 100 11.35 2.50 Yes Fri Dinner 2 0.220264 101 15.38 3.00 Yes Fri Dinner 2 0.195059 220 12.16 2.20 Yes Fri Lunch 2 0.180921 221 13.42 3.48 Yes Fri Lunch 2 0.259314 222 8.58 1.92 Yes Fri Lunch 1 0.223776 224 13.42 1.58 Yes Fri Lunch 2 0.117735 225 16.27 2.50 Yes Fri Lunch 2 0.153657 226 10.09 2.00 Yes Fri Lunch 2 0.198216), (('Sat', 'No'), total_bill tip smoker day time size tip_pct 19 20.65 3.35 No Sat Dinner 3 0.162228 20 17.92 4.08 No Sat Dinner 2 0.227679 21 20.29 2.75 No Sat Dinner 2 0.135535 22 15.77 2.23 No Sat Dinner 2 0.141408 23 39.42 7.58 No Sat Dinner 4 0.192288 24 19.82 3.18 No Sat Dinner 2 0.160444 25 17.81 2.34 No Sat Dinner 4 0.131387 26 13.37 2.00 No Sat Dinner 2 0.149589 27 12.69 2.00 No Sat Dinner 2 0.157604 28 21.70 4.30 No Sat Dinner 2 0.198157 29 19.65 3.00 No Sat Dinner 2 0.152672 30 9.55 1.45 No Sat Dinner 2 0.151832 31 18.35 2.50 No Sat Dinner 4 0.136240 32 15.06 3.00 No Sat Dinner 2 0.199203 33 20.69 2.45 No Sat Dinner 4 0.118415 34 17.78 3.27 No Sat Dinner 2 0.183915 35 24.06 3.60 No Sat Dinner 3 0.149626 36 16.31 2.00 No Sat Dinner 3 0.122624 37 16.93 3.07 No Sat Dinner 3 0.181335 38 18.69 2.31 No Sat Dinner 3 0.123596 39 31.27 5.00 No Sat Dinner 3 0.159898 40 16.04 2.24 No Sat Dinner 3 0.139651 57 26.41 1.50 No Sat Dinner 2 0.056797 59 48.27 6.73 No Sat Dinner 4 0.139424 64 17.59 2.64 No Sat Dinner 3 0.150085 65 20.08 3.15 No Sat Dinner 3 0.156873 66 16.45 2.47 No Sat Dinner 2 0.150152 68 20.23 2.01 No Sat Dinner 2 0.099357 70 12.02 1.97 No Sat Dinner 2 0.163894 71 17.07 3.00 No Sat Dinner 3 0.175747 74 14.73 2.20 No Sat Dinner 2 0.149355 75 10.51 1.25 No Sat Dinner 2 0.118934 104 20.92 4.08 No Sat Dinner 2 0.195029 108 18.24 3.76 No Sat Dinner 2 0.206140 110 14.00 3.00 No Sat Dinner 2 0.214286 111 7.25 1.00 No Sat Dinner 1 0.137931 212 48.33 9.00 No Sat Dinner 4 0.186220 227 20.45 3.00 No Sat Dinner 4 0.146699 228 13.28 2.72 No Sat Dinner 2 0.204819 232 11.61 3.39 No Sat Dinner 2 0.291990 233 10.77 1.47 No Sat Dinner 2 0.136490 235 10.07 1.25 No Sat Dinner 2 0.124131 238 35.83 4.67 No Sat Dinner 3 0.130338 239 29.03 5.92 No Sat Dinner 3 0.203927 242 17.82 1.75 No Sat Dinner 2 0.098204), (('Sat', 'Yes'), total_bill tip smoker day time size tip_pct 56 38.01 3.00 Yes Sat Dinner 4 0.078927 58 11.24 1.76 Yes Sat Dinner 2 0.156584 60 20.29 3.21 Yes Sat Dinner 2 0.158206 61 13.81 2.00 Yes Sat Dinner 2 0.144823 62 11.02 1.98 Yes Sat Dinner 2 0.179673 63 18.29 3.76 Yes Sat Dinner 4 0.205577 67 3.07 1.00 Yes Sat Dinner 1 0.325733 69 15.01 2.09 Yes Sat Dinner 2 0.139241 72 26.86 3.14 Yes Sat Dinner 2 0.116902 73 25.28 5.00 Yes Sat Dinner 2 0.197785 76 17.92 3.08 Yes Sat Dinner 2 0.171875 102 44.30 2.50 Yes Sat Dinner 3 0.056433 103 22.42 3.48 Yes Sat Dinner 2 0.155219 105 15.36 1.64 Yes Sat Dinner 2 0.106771 106 20.49 4.06 Yes Sat Dinner 2 0.198145 107 25.21 4.29 Yes Sat Dinner 2 0.170171 109 14.31 4.00 Yes Sat Dinner 2 0.279525 168 10.59 1.61 Yes Sat Dinner 2 0.152030 169 10.63 2.00 Yes Sat Dinner 2 0.188147 170 50.81 10.00 Yes Sat Dinner 3 0.196812 171 15.81 3.16 Yes Sat Dinner 2 0.199873 206 26.59 3.41 Yes Sat Dinner 3 0.128244 207 38.73 3.00 Yes Sat Dinner 4 0.077459 208 24.27 2.03 Yes Sat Dinner 2 0.083642 209 12.76 2.23 Yes Sat Dinner 2 0.174765 210 30.06 2.00 Yes Sat Dinner 3 0.066534 211 25.89 5.16 Yes Sat Dinner 4 0.199305 213 13.27 2.50 Yes Sat Dinner 2 0.188395 214 28.17 6.50 Yes Sat Dinner 3 0.230742 215 12.90 1.10 Yes Sat Dinner 2 0.085271 216 28.15 3.00 Yes Sat Dinner 5 0.106572 217 11.59 1.50 Yes Sat Dinner 2 0.129422 218 7.74 1.44 Yes Sat Dinner 2 0.186047 219 30.14 3.09 Yes Sat Dinner 4 0.102522 229 22.12 2.88 Yes Sat Dinner 2 0.130199 230 24.01 2.00 Yes Sat Dinner 4 0.083299 231 15.69 3.00 Yes Sat Dinner 3 0.191205 234 15.53 3.00 Yes Sat Dinner 2 0.193175 236 12.60 1.00 Yes Sat Dinner 2 0.079365 237 32.83 1.17 Yes Sat Dinner 2 0.035638 240 27.18 2.00 Yes Sat Dinner 2 0.073584 241 22.67 2.00 Yes Sat Dinner 2 0.088222), (('Sun', 'No'), 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 6 8.77 2.00 No Sun Dinner 2 0.228050 7 26.88 3.12 No Sun Dinner 4 0.116071 8 15.04 1.96 No Sun Dinner 2 0.130319 9 14.78 3.23 No Sun Dinner 2 0.218539 10 10.27 1.71 No Sun Dinner 2 0.166504 11 35.26 5.00 No Sun Dinner 4 0.141804 12 15.42 1.57 No Sun Dinner 2 0.101816 13 18.43 3.00 No Sun Dinner 4 0.162778 14 14.83 3.02 No Sun Dinner 2 0.203641 15 21.58 3.92 No Sun Dinner 2 0.181650 16 10.33 1.67 No Sun Dinner 3 0.161665 17 16.29 3.71 No Sun Dinner 3 0.227747 18 16.97 3.50 No Sun Dinner 3 0.206246 41 17.46 2.54 No Sun Dinner 2 0.145475 42 13.94 3.06 No Sun Dinner 2 0.219512 43 9.68 1.32 No Sun Dinner 2 0.136364 44 30.40 5.60 No Sun Dinner 4 0.184211 45 18.29 3.00 No Sun Dinner 2 0.164024 46 22.23 5.00 No Sun Dinner 2 0.224921 47 32.40 6.00 No Sun Dinner 4 0.185185 48 28.55 2.05 No Sun Dinner 3 0.071804 49 18.04 3.00 No Sun Dinner 2 0.166297 50 12.54 2.50 No Sun Dinner 2 0.199362 51 10.29 2.60 No Sun Dinner 2 0.252672 52 34.81 5.20 No Sun Dinner 4 0.149382 53 9.94 1.56 No Sun Dinner 2 0.156942 54 25.56 4.34 No Sun Dinner 4 0.169797 55 19.49 3.51 No Sun Dinner 2 0.180092 112 38.07 4.00 No Sun Dinner 3 0.105070 113 23.95 2.55 No Sun Dinner 2 0.106472 114 25.71 4.00 No Sun Dinner 3 0.155581 115 17.31 3.50 No Sun Dinner 2 0.202195 116 29.93 5.07 No Sun Dinner 4 0.169395 150 14.07 2.50 No Sun Dinner 2 0.177683 151 13.13 2.00 No Sun Dinner 2 0.152323 152 17.26 2.74 No Sun Dinner 3 0.158749 153 24.55 2.00 No Sun Dinner 4 0.081466 154 19.77 2.00 No Sun Dinner 4 0.101163 155 29.85 5.14 No Sun Dinner 5 0.172194 156 48.17 5.00 No Sun Dinner 6 0.103799 157 25.00 3.75 No Sun Dinner 4 0.150000 158 13.39 2.61 No Sun Dinner 2 0.194922 159 16.49 2.00 No Sun Dinner 4 0.121286 160 21.50 3.50 No Sun Dinner 4 0.162791 161 12.66 2.50 No Sun Dinner 2 0.197472 162 16.21 2.00 No Sun Dinner 3 0.123381 163 13.81 2.00 No Sun Dinner 2 0.144823 165 24.52 3.48 No Sun Dinner 3 0.141925 166 20.76 2.24 No Sun Dinner 2 0.107900 167 31.71 4.50 No Sun Dinner 4 0.141911 185 20.69 5.00 No Sun Dinner 5 0.241663), (('Sun', 'Yes'), total_bill tip smoker day time size tip_pct 164 17.51 3.00 Yes Sun Dinner 2 0.171331 172 7.25 5.15 Yes Sun Dinner 2 0.710345 173 31.85 3.18 Yes Sun Dinner 2 0.099843 174 16.82 4.00 Yes Sun Dinner 2 0.237812 175 32.90 3.11 Yes Sun Dinner 2 0.094529 176 17.89 2.00 Yes Sun Dinner 2 0.111794 177 14.48 2.00 Yes Sun Dinner 2 0.138122 178 9.60 4.00 Yes Sun Dinner 2 0.416667 179 34.63 3.55 Yes Sun Dinner 2 0.102512 180 34.65 3.68 Yes Sun Dinner 4 0.106205 181 23.33 5.65 Yes Sun Dinner 2 0.242177 182 45.35 3.50 Yes Sun Dinner 3 0.077178 183 23.17 6.50 Yes Sun Dinner 4 0.280535 184 40.55 3.00 Yes Sun Dinner 2 0.073983 186 20.90 3.50 Yes Sun Dinner 3 0.167464 187 30.46 2.00 Yes Sun Dinner 5 0.065660 188 18.15 3.50 Yes Sun Dinner 3 0.192837 189 23.10 4.00 Yes Sun Dinner 3 0.173160 190 15.69 1.50 Yes Sun Dinner 2 0.095602), (('Thur', 'No'), total_bill tip smoker day time size tip_pct 77 27.20 4.00 No Thur Lunch 4 0.147059 78 22.76 3.00 No Thur Lunch 2 0.131810 79 17.29 2.71 No Thur Lunch 2 0.156738 81 16.66 3.40 No Thur Lunch 2 0.204082 82 10.07 1.83 No Thur Lunch 1 0.181728 84 15.98 2.03 No Thur Lunch 2 0.127034 85 34.83 5.17 No Thur Lunch 4 0.148435 86 13.03 2.00 No Thur Lunch 2 0.153492 87 18.28 4.00 No Thur Lunch 2 0.218818 88 24.71 5.85 No Thur Lunch 2 0.236746 89 21.16 3.00 No Thur Lunch 2 0.141777 117 10.65 1.50 No Thur Lunch 2 0.140845 118 12.43 1.80 No Thur Lunch 2 0.144811 119 24.08 2.92 No Thur Lunch 4 0.121262 120 11.69 2.31 No Thur Lunch 2 0.197605 121 13.42 1.68 No Thur Lunch 2 0.125186 122 14.26 2.50 No Thur Lunch 2 0.175316 123 15.95 2.00 No Thur Lunch 2 0.125392 124 12.48 2.52 No Thur Lunch 2 0.201923 125 29.80 4.20 No Thur Lunch 6 0.140940 126 8.52 1.48 No Thur Lunch 2 0.173709 127 14.52 2.00 No Thur Lunch 2 0.137741 128 11.38 2.00 No Thur Lunch 2 0.175747 129 22.82 2.18 No Thur Lunch 3 0.095530 130 19.08 1.50 No Thur Lunch 2 0.078616 131 20.27 2.83 No Thur Lunch 2 0.139615 132 11.17 1.50 No Thur Lunch 2 0.134288 133 12.26 2.00 No Thur Lunch 2 0.163132 134 18.26 3.25 No Thur Lunch 2 0.177985 135 8.51 1.25 No Thur Lunch 2 0.146886 136 10.33 2.00 No Thur Lunch 2 0.193611 137 14.15 2.00 No Thur Lunch 2 0.141343 139 13.16 2.75 No Thur Lunch 2 0.208967 140 17.47 3.50 No Thur Lunch 2 0.200343 141 34.30 6.70 No Thur Lunch 6 0.195335 142 41.19 5.00 No Thur Lunch 5 0.121389 143 27.05 5.00 No Thur Lunch 6 0.184843 144 16.43 2.30 No Thur Lunch 2 0.139988 145 8.35 1.50 No Thur Lunch 2 0.179641 146 18.64 1.36 No Thur Lunch 3 0.072961 147 11.87 1.63 No Thur Lunch 2 0.137321 148 9.78 1.73 No Thur Lunch 2 0.176892 149 7.51 2.00 No Thur Lunch 2 0.266312 195 7.56 1.44 No Thur Lunch 2 0.190476 243 18.78 3.00 No Thur Dinner 2 0.159744), (('Thur', 'Yes'), total_bill tip smoker day time size tip_pct 80 19.44 3.00 Yes Thur Lunch 2 0.154321 83 32.68 5.00 Yes Thur Lunch 2 0.152999 138 16.00 2.00 Yes Thur Lunch 2 0.125000 191 19.81 4.19 Yes Thur Lunch 2 0.211509 192 28.44 2.56 Yes Thur Lunch 2 0.090014 193 15.48 2.02 Yes Thur Lunch 2 0.130491 194 16.58 4.00 Yes Thur Lunch 2 0.241255 196 10.34 2.00 Yes Thur Lunch 2 0.193424 197 43.11 5.00 Yes Thur Lunch 4 0.115982 198 13.00 2.00 Yes Thur Lunch 2 0.153846 199 13.51 2.00 Yes Thur Lunch 2 0.148038 200 18.71 4.00 Yes Thur Lunch 3 0.213789 201 12.74 2.01 Yes Thur Lunch 2 0.157771 202 13.00 2.00 Yes Thur Lunch 2 0.153846 203 16.40 2.50 Yes Thur Lunch 2 0.152439 204 20.53 4.00 Yes Thur Lunch 4 0.194837 205 16.47 3.23 Yes Thur Lunch 3 0.196114)]
함수열을 문자열로 넘기기
grouped_pct = grouped['tip_pct']
list(grouped_pct)
[(('Fri', 'No'), 91 0.155625 94 0.142857 99 0.120385 223 0.187735 Name: tip_pct, dtype: float64), (('Fri', 'Yes'), 90 0.103555 92 0.173913 93 0.263480 95 0.117750 96 0.146628 97 0.124688 98 0.142789 100 0.220264 101 0.195059 220 0.180921 221 0.259314 222 0.223776 224 0.117735 225 0.153657 226 0.198216 Name: tip_pct, dtype: float64), (('Sat', 'No'), 19 0.162228 20 0.227679 21 0.135535 22 0.141408 23 0.192288 24 0.160444 25 0.131387 26 0.149589 27 0.157604 28 0.198157 29 0.152672 30 0.151832 31 0.136240 32 0.199203 33 0.118415 34 0.183915 35 0.149626 36 0.122624 37 0.181335 38 0.123596 39 0.159898 40 0.139651 57 0.056797 59 0.139424 64 0.150085 65 0.156873 66 0.150152 68 0.099357 70 0.163894 71 0.175747 74 0.149355 75 0.118934 104 0.195029 108 0.206140 110 0.214286 111 0.137931 212 0.186220 227 0.146699 228 0.204819 232 0.291990 233 0.136490 235 0.124131 238 0.130338 239 0.203927 242 0.098204 Name: tip_pct, dtype: float64), (('Sat', 'Yes'), 56 0.078927 58 0.156584 60 0.158206 61 0.144823 62 0.179673 63 0.205577 67 0.325733 69 0.139241 72 0.116902 73 0.197785 76 0.171875 102 0.056433 103 0.155219 105 0.106771 106 0.198145 107 0.170171 109 0.279525 168 0.152030 169 0.188147 170 0.196812 171 0.199873 206 0.128244 207 0.077459 208 0.083642 209 0.174765 210 0.066534 211 0.199305 213 0.188395 214 0.230742 215 0.085271 216 0.106572 217 0.129422 218 0.186047 219 0.102522 229 0.130199 230 0.083299 231 0.191205 234 0.193175 236 0.079365 237 0.035638 240 0.073584 241 0.088222 Name: tip_pct, dtype: float64), (('Sun', 'No'), 0 0.059447 1 0.160542 2 0.166587 3 0.139780 4 0.146808 5 0.186240 6 0.228050 7 0.116071 8 0.130319 9 0.218539 10 0.166504 11 0.141804 12 0.101816 13 0.162778 14 0.203641 15 0.181650 16 0.161665 17 0.227747 18 0.206246 41 0.145475 42 0.219512 43 0.136364 44 0.184211 45 0.164024 46 0.224921 47 0.185185 48 0.071804 49 0.166297 50 0.199362 51 0.252672 52 0.149382 53 0.156942 54 0.169797 55 0.180092 112 0.105070 113 0.106472 114 0.155581 115 0.202195 116 0.169395 150 0.177683 151 0.152323 152 0.158749 153 0.081466 154 0.101163 155 0.172194 156 0.103799 157 0.150000 158 0.194922 159 0.121286 160 0.162791 161 0.197472 162 0.123381 163 0.144823 165 0.141925 166 0.107900 167 0.141911 185 0.241663 Name: tip_pct, dtype: float64), (('Sun', 'Yes'), 164 0.171331 172 0.710345 173 0.099843 174 0.237812 175 0.094529 176 0.111794 177 0.138122 178 0.416667 179 0.102512 180 0.106205 181 0.242177 182 0.077178 183 0.280535 184 0.073983 186 0.167464 187 0.065660 188 0.192837 189 0.173160 190 0.095602 Name: tip_pct, dtype: float64), (('Thur', 'No'), 77 0.147059 78 0.131810 79 0.156738 81 0.204082 82 0.181728 84 0.127034 85 0.148435 86 0.153492 87 0.218818 88 0.236746 89 0.141777 117 0.140845 118 0.144811 119 0.121262 120 0.197605 121 0.125186 122 0.175316 123 0.125392 124 0.201923 125 0.140940 126 0.173709 127 0.137741 128 0.175747 129 0.095530 130 0.078616 131 0.139615 132 0.134288 133 0.163132 134 0.177985 135 0.146886 136 0.193611 137 0.141343 139 0.208967 140 0.200343 141 0.195335 142 0.121389 143 0.184843 144 0.139988 145 0.179641 146 0.072961 147 0.137321 148 0.176892 149 0.266312 195 0.190476 243 0.159744 Name: tip_pct, dtype: float64), (('Thur', 'Yes'), 80 0.154321 83 0.152999 138 0.125000 191 0.211509 192 0.090014 193 0.130491 194 0.241255 196 0.193424 197 0.115982 198 0.153846 199 0.148038 200 0.213789 201 0.157771 202 0.153846 203 0.152439 204 0.194837 205 0.196114 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
만일 함수 목록이나 함수 이름을 넘기면 함수 이름을 컬럼 이름으로 하는 DataFrame을 얻게 됨
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 |
여기서는 데이터 그룹에 대해 독립적으로 적용하기 위해 agg에 집계함수들의 리스트를 넘김
GropuBy 객체에서 자동으로 지정하는 컬럼 이름을 그대로 쓰지 않아도 됌
lambda 함수는 이름(함수 이름은 name 속성으로 확인 가능)이 '
이때 이름과 함수가 담긴 (name, function) 튜플의 리스트를 넘기면 각 튜플에서 첫 번째 원소가 DataFrame에서 컬럼 이름으로 사용됨
(2개의 튜플을 가지는 리스트가 순서대로 매핑)
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은 컬럼마다 다른 함수를 적용하거나 여러 개의 함수를 모든 컬럼에 적용 가능
tip_pct와 total_bill 컬럼에 대해 동일한 세 가지 통계를 계산한다고 가정
functions = ['count', 'mean', 'max']
result = grouped['tip_pct', 'total_bill'].agg(functions)
C:\Users\user\AppData\Local\Temp\ipykernel_14620\1540724723.py:1: FutureWarning: Indexing with multiple keys (implicitly converted to a tuple of keys) will be deprecated, use a list instead. 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은 계층적인 컬럼을 가지고 있으며
이는 각 컬럼을 따로 계산한 다음 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 |
위에서처럼 컬럼 이름과 메서드가 담긴 튜플의 리스트를 넘기는 것도 가능
ftuples = [('Durchschnitt', 'mean'), ('Abweichung', np.var)]
grouped['tip_pct', 'total_bill'].agg(ftuples)
C:\Users\user\AppData\Local\Temp\ipykernel_14620\514018043.py:1: FutureWarning: Indexing with multiple keys (implicitly converted to a tuple of keys) will be deprecated, use a list instead. 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 메서드에 컬럼 이름에 대응하는 함수가 들어 있는 사전 넘기기
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은 계층적인 컬럼을 가지게 됨
10.2.2 색인되지 않은 형태로 집계된 데이터 반환¶
as_index=False¶
지금까지 살펴본 모든 예제에서 집계된 데이터는 유일한 그룹키 조합으로 색인(어떤 경우에는 계층적 색인)되어 반환
하지만 항상 이런 동작을 기대하는 것은 아니므로 groupby 메서드에 as_index=False를 넘겨서 색인되지 않도록 할 수 있음
tips
total_bill | tip | smoker | day | time | size | |
---|---|---|---|---|---|---|
0 | 16.99 | 1.01 | No | Sun | Dinner | 2 |
1 | 10.34 | 1.66 | No | Sun | Dinner | 3 |
2 | 21.01 | 3.50 | No | Sun | Dinner | 3 |
3 | 23.68 | 3.31 | No | Sun | Dinner | 2 |
4 | 24.59 | 3.61 | No | Sun | Dinner | 4 |
... | ... | ... | ... | ... | ... | ... |
239 | 29.03 | 5.92 | No | Sat | Dinner | 3 |
240 | 27.18 | 2.00 | Yes | Sat | Dinner | 2 |
241 | 22.67 | 2.00 | Yes | Sat | Dinner | 2 |
242 | 17.82 | 1.75 | No | Sat | Dinner | 2 |
243 | 18.78 | 3.00 | No | Thur | Dinner | 2 |
244 rows × 6 columns
tips.groupby(['day', 'smoker'], as_index=False).mean()
C:\Users\user\AppData\Local\Temp\ipykernel_17844\2496195394.py:1: FutureWarning: The default value of numeric_only in DataFrameGroupBy.mean is deprecated. In a future version, numeric_only will default to False. Either specify numeric_only or select only columns which should be valid for the function. tips.groupby(['day', 'smoker'], as_index=False).mean()
day | smoker | total_bill | tip | size | |
---|---|---|---|---|---|
0 | Fri | No | 18.420000 | 2.812500 | 2.250000 |
1 | Fri | Yes | 16.813333 | 2.714000 | 2.066667 |
2 | Sat | No | 19.661778 | 3.102889 | 2.555556 |
3 | Sat | Yes | 21.276667 | 2.875476 | 2.476190 |
4 | Sun | No | 20.506667 | 3.167895 | 2.929825 |
5 | Sun | Yes | 24.120000 | 3.516842 | 2.578947 |
6 | Thur | No | 17.113111 | 2.673778 | 2.488889 |
7 | Thur | Yes | 19.190588 | 3.030000 | 2.352941 |
물론 이렇게 하지 않고 색인된 결과에 대해 reset_index 메서드를 호출해서 같은 결과 얻을 수 있음
as_index=False 옵션 사용 시 불필요한 계산 피할 수 있음
10.3 Apply: 일반적인 분리-적용-병합¶
apply 메서드는 객체를 여러 조각으로 나누고, 전달된 함수를 각 조각에 일괄 적용한 후 이를 다시 합침
앞서 살펴본 팁 데이터에서 그룹별 상위 5개의 tip_pct 값을 골라보자.
우선 특정 컬럼에서 가장 큰 값을 가지는 로우를 선택하는 함수를 바로 작성
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 |
이제 흡연자(smoker) 그룹에 대해 이 함수(top)를 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 |
위 결과를 보면 top 함수가 나뉘어진 DataFrame의 각 부분에 모두 적용이 되었고,
pandas.concat을 이용해서 하나로 합쳐진 다음 그룹 이름표가 붙었음
그리하여 결과는 계층적 색인을 가지게 되고 내부 색인 원본 DataFrame의 색인값을 가짐
만일 apply 메서드로 넘길 함수가 추가적인 인자를 받는다면 함수 이름 뒤에 붙여서 넘겨주면 됨
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 |
이 책 앞부분에서 GroupBy 객체에 describe 메서드를 호출했던 적이 있음
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
describe 같은 메서드를 호출하면 GroupBy 내부적으로 다음과 같은 단계 수행
list(grouped)
[(('Fri', 'No'), total_bill tip smoker day time size tip_pct 91 22.49 3.50 No Fri Dinner 2 0.155625 94 22.75 3.25 No Fri Dinner 2 0.142857 99 12.46 1.50 No Fri Dinner 2 0.120385 223 15.98 3.00 No Fri Lunch 3 0.187735), (('Fri', 'Yes'), total_bill tip smoker day time size tip_pct 90 28.97 3.00 Yes Fri Dinner 2 0.103555 92 5.75 1.00 Yes Fri Dinner 2 0.173913 93 16.32 4.30 Yes Fri Dinner 2 0.263480 95 40.17 4.73 Yes Fri Dinner 4 0.117750 96 27.28 4.00 Yes Fri Dinner 2 0.146628 97 12.03 1.50 Yes Fri Dinner 2 0.124688 98 21.01 3.00 Yes Fri Dinner 2 0.142789 100 11.35 2.50 Yes Fri Dinner 2 0.220264 101 15.38 3.00 Yes Fri Dinner 2 0.195059 220 12.16 2.20 Yes Fri Lunch 2 0.180921 221 13.42 3.48 Yes Fri Lunch 2 0.259314 222 8.58 1.92 Yes Fri Lunch 1 0.223776 224 13.42 1.58 Yes Fri Lunch 2 0.117735 225 16.27 2.50 Yes Fri Lunch 2 0.153657 226 10.09 2.00 Yes Fri Lunch 2 0.198216), (('Sat', 'No'), total_bill tip smoker day time size tip_pct 19 20.65 3.35 No Sat Dinner 3 0.162228 20 17.92 4.08 No Sat Dinner 2 0.227679 21 20.29 2.75 No Sat Dinner 2 0.135535 22 15.77 2.23 No Sat Dinner 2 0.141408 23 39.42 7.58 No Sat Dinner 4 0.192288 24 19.82 3.18 No Sat Dinner 2 0.160444 25 17.81 2.34 No Sat Dinner 4 0.131387 26 13.37 2.00 No Sat Dinner 2 0.149589 27 12.69 2.00 No Sat Dinner 2 0.157604 28 21.70 4.30 No Sat Dinner 2 0.198157 29 19.65 3.00 No Sat Dinner 2 0.152672 30 9.55 1.45 No Sat Dinner 2 0.151832 31 18.35 2.50 No Sat Dinner 4 0.136240 32 15.06 3.00 No Sat Dinner 2 0.199203 33 20.69 2.45 No Sat Dinner 4 0.118415 34 17.78 3.27 No Sat Dinner 2 0.183915 35 24.06 3.60 No Sat Dinner 3 0.149626 36 16.31 2.00 No Sat Dinner 3 0.122624 37 16.93 3.07 No Sat Dinner 3 0.181335 38 18.69 2.31 No Sat Dinner 3 0.123596 39 31.27 5.00 No Sat Dinner 3 0.159898 40 16.04 2.24 No Sat Dinner 3 0.139651 57 26.41 1.50 No Sat Dinner 2 0.056797 59 48.27 6.73 No Sat Dinner 4 0.139424 64 17.59 2.64 No Sat Dinner 3 0.150085 65 20.08 3.15 No Sat Dinner 3 0.156873 66 16.45 2.47 No Sat Dinner 2 0.150152 68 20.23 2.01 No Sat Dinner 2 0.099357 70 12.02 1.97 No Sat Dinner 2 0.163894 71 17.07 3.00 No Sat Dinner 3 0.175747 74 14.73 2.20 No Sat Dinner 2 0.149355 75 10.51 1.25 No Sat Dinner 2 0.118934 104 20.92 4.08 No Sat Dinner 2 0.195029 108 18.24 3.76 No Sat Dinner 2 0.206140 110 14.00 3.00 No Sat Dinner 2 0.214286 111 7.25 1.00 No Sat Dinner 1 0.137931 212 48.33 9.00 No Sat Dinner 4 0.186220 227 20.45 3.00 No Sat Dinner 4 0.146699 228 13.28 2.72 No Sat Dinner 2 0.204819 232 11.61 3.39 No Sat Dinner 2 0.291990 233 10.77 1.47 No Sat Dinner 2 0.136490 235 10.07 1.25 No Sat Dinner 2 0.124131 238 35.83 4.67 No Sat Dinner 3 0.130338 239 29.03 5.92 No Sat Dinner 3 0.203927 242 17.82 1.75 No Sat Dinner 2 0.098204), (('Sat', 'Yes'), total_bill tip smoker day time size tip_pct 56 38.01 3.00 Yes Sat Dinner 4 0.078927 58 11.24 1.76 Yes Sat Dinner 2 0.156584 60 20.29 3.21 Yes Sat Dinner 2 0.158206 61 13.81 2.00 Yes Sat Dinner 2 0.144823 62 11.02 1.98 Yes Sat Dinner 2 0.179673 63 18.29 3.76 Yes Sat Dinner 4 0.205577 67 3.07 1.00 Yes Sat Dinner 1 0.325733 69 15.01 2.09 Yes Sat Dinner 2 0.139241 72 26.86 3.14 Yes Sat Dinner 2 0.116902 73 25.28 5.00 Yes Sat Dinner 2 0.197785 76 17.92 3.08 Yes Sat Dinner 2 0.171875 102 44.30 2.50 Yes Sat Dinner 3 0.056433 103 22.42 3.48 Yes Sat Dinner 2 0.155219 105 15.36 1.64 Yes Sat Dinner 2 0.106771 106 20.49 4.06 Yes Sat Dinner 2 0.198145 107 25.21 4.29 Yes Sat Dinner 2 0.170171 109 14.31 4.00 Yes Sat Dinner 2 0.279525 168 10.59 1.61 Yes Sat Dinner 2 0.152030 169 10.63 2.00 Yes Sat Dinner 2 0.188147 170 50.81 10.00 Yes Sat Dinner 3 0.196812 171 15.81 3.16 Yes Sat Dinner 2 0.199873 206 26.59 3.41 Yes Sat Dinner 3 0.128244 207 38.73 3.00 Yes Sat Dinner 4 0.077459 208 24.27 2.03 Yes Sat Dinner 2 0.083642 209 12.76 2.23 Yes Sat Dinner 2 0.174765 210 30.06 2.00 Yes Sat Dinner 3 0.066534 211 25.89 5.16 Yes Sat Dinner 4 0.199305 213 13.27 2.50 Yes Sat Dinner 2 0.188395 214 28.17 6.50 Yes Sat Dinner 3 0.230742 215 12.90 1.10 Yes Sat Dinner 2 0.085271 216 28.15 3.00 Yes Sat Dinner 5 0.106572 217 11.59 1.50 Yes Sat Dinner 2 0.129422 218 7.74 1.44 Yes Sat Dinner 2 0.186047 219 30.14 3.09 Yes Sat Dinner 4 0.102522 229 22.12 2.88 Yes Sat Dinner 2 0.130199 230 24.01 2.00 Yes Sat Dinner 4 0.083299 231 15.69 3.00 Yes Sat Dinner 3 0.191205 234 15.53 3.00 Yes Sat Dinner 2 0.193175 236 12.60 1.00 Yes Sat Dinner 2 0.079365 237 32.83 1.17 Yes Sat Dinner 2 0.035638 240 27.18 2.00 Yes Sat Dinner 2 0.073584 241 22.67 2.00 Yes Sat Dinner 2 0.088222), (('Sun', 'No'), 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 6 8.77 2.00 No Sun Dinner 2 0.228050 7 26.88 3.12 No Sun Dinner 4 0.116071 8 15.04 1.96 No Sun Dinner 2 0.130319 9 14.78 3.23 No Sun Dinner 2 0.218539 10 10.27 1.71 No Sun Dinner 2 0.166504 11 35.26 5.00 No Sun Dinner 4 0.141804 12 15.42 1.57 No Sun Dinner 2 0.101816 13 18.43 3.00 No Sun Dinner 4 0.162778 14 14.83 3.02 No Sun Dinner 2 0.203641 15 21.58 3.92 No Sun Dinner 2 0.181650 16 10.33 1.67 No Sun Dinner 3 0.161665 17 16.29 3.71 No Sun Dinner 3 0.227747 18 16.97 3.50 No Sun Dinner 3 0.206246 41 17.46 2.54 No Sun Dinner 2 0.145475 42 13.94 3.06 No Sun Dinner 2 0.219512 43 9.68 1.32 No Sun Dinner 2 0.136364 44 30.40 5.60 No Sun Dinner 4 0.184211 45 18.29 3.00 No Sun Dinner 2 0.164024 46 22.23 5.00 No Sun Dinner 2 0.224921 47 32.40 6.00 No Sun Dinner 4 0.185185 48 28.55 2.05 No Sun Dinner 3 0.071804 49 18.04 3.00 No Sun Dinner 2 0.166297 50 12.54 2.50 No Sun Dinner 2 0.199362 51 10.29 2.60 No Sun Dinner 2 0.252672 52 34.81 5.20 No Sun Dinner 4 0.149382 53 9.94 1.56 No Sun Dinner 2 0.156942 54 25.56 4.34 No Sun Dinner 4 0.169797 55 19.49 3.51 No Sun Dinner 2 0.180092 112 38.07 4.00 No Sun Dinner 3 0.105070 113 23.95 2.55 No Sun Dinner 2 0.106472 114 25.71 4.00 No Sun Dinner 3 0.155581 115 17.31 3.50 No Sun Dinner 2 0.202195 116 29.93 5.07 No Sun Dinner 4 0.169395 150 14.07 2.50 No Sun Dinner 2 0.177683 151 13.13 2.00 No Sun Dinner 2 0.152323 152 17.26 2.74 No Sun Dinner 3 0.158749 153 24.55 2.00 No Sun Dinner 4 0.081466 154 19.77 2.00 No Sun Dinner 4 0.101163 155 29.85 5.14 No Sun Dinner 5 0.172194 156 48.17 5.00 No Sun Dinner 6 0.103799 157 25.00 3.75 No Sun Dinner 4 0.150000 158 13.39 2.61 No Sun Dinner 2 0.194922 159 16.49 2.00 No Sun Dinner 4 0.121286 160 21.50 3.50 No Sun Dinner 4 0.162791 161 12.66 2.50 No Sun Dinner 2 0.197472 162 16.21 2.00 No Sun Dinner 3 0.123381 163 13.81 2.00 No Sun Dinner 2 0.144823 165 24.52 3.48 No Sun Dinner 3 0.141925 166 20.76 2.24 No Sun Dinner 2 0.107900 167 31.71 4.50 No Sun Dinner 4 0.141911 185 20.69 5.00 No Sun Dinner 5 0.241663), (('Sun', 'Yes'), total_bill tip smoker day time size tip_pct 164 17.51 3.00 Yes Sun Dinner 2 0.171331 172 7.25 5.15 Yes Sun Dinner 2 0.710345 173 31.85 3.18 Yes Sun Dinner 2 0.099843 174 16.82 4.00 Yes Sun Dinner 2 0.237812 175 32.90 3.11 Yes Sun Dinner 2 0.094529 176 17.89 2.00 Yes Sun Dinner 2 0.111794 177 14.48 2.00 Yes Sun Dinner 2 0.138122 178 9.60 4.00 Yes Sun Dinner 2 0.416667 179 34.63 3.55 Yes Sun Dinner 2 0.102512 180 34.65 3.68 Yes Sun Dinner 4 0.106205 181 23.33 5.65 Yes Sun Dinner 2 0.242177 182 45.35 3.50 Yes Sun Dinner 3 0.077178 183 23.17 6.50 Yes Sun Dinner 4 0.280535 184 40.55 3.00 Yes Sun Dinner 2 0.073983 186 20.90 3.50 Yes Sun Dinner 3 0.167464 187 30.46 2.00 Yes Sun Dinner 5 0.065660 188 18.15 3.50 Yes Sun Dinner 3 0.192837 189 23.10 4.00 Yes Sun Dinner 3 0.173160 190 15.69 1.50 Yes Sun Dinner 2 0.095602), (('Thur', 'No'), total_bill tip smoker day time size tip_pct 77 27.20 4.00 No Thur Lunch 4 0.147059 78 22.76 3.00 No Thur Lunch 2 0.131810 79 17.29 2.71 No Thur Lunch 2 0.156738 81 16.66 3.40 No Thur Lunch 2 0.204082 82 10.07 1.83 No Thur Lunch 1 0.181728 84 15.98 2.03 No Thur Lunch 2 0.127034 85 34.83 5.17 No Thur Lunch 4 0.148435 86 13.03 2.00 No Thur Lunch 2 0.153492 87 18.28 4.00 No Thur Lunch 2 0.218818 88 24.71 5.85 No Thur Lunch 2 0.236746 89 21.16 3.00 No Thur Lunch 2 0.141777 117 10.65 1.50 No Thur Lunch 2 0.140845 118 12.43 1.80 No Thur Lunch 2 0.144811 119 24.08 2.92 No Thur Lunch 4 0.121262 120 11.69 2.31 No Thur Lunch 2 0.197605 121 13.42 1.68 No Thur Lunch 2 0.125186 122 14.26 2.50 No Thur Lunch 2 0.175316 123 15.95 2.00 No Thur Lunch 2 0.125392 124 12.48 2.52 No Thur Lunch 2 0.201923 125 29.80 4.20 No Thur Lunch 6 0.140940 126 8.52 1.48 No Thur Lunch 2 0.173709 127 14.52 2.00 No Thur Lunch 2 0.137741 128 11.38 2.00 No Thur Lunch 2 0.175747 129 22.82 2.18 No Thur Lunch 3 0.095530 130 19.08 1.50 No Thur Lunch 2 0.078616 131 20.27 2.83 No Thur Lunch 2 0.139615 132 11.17 1.50 No Thur Lunch 2 0.134288 133 12.26 2.00 No Thur Lunch 2 0.163132 134 18.26 3.25 No Thur Lunch 2 0.177985 135 8.51 1.25 No Thur Lunch 2 0.146886 136 10.33 2.00 No Thur Lunch 2 0.193611 137 14.15 2.00 No Thur Lunch 2 0.141343 139 13.16 2.75 No Thur Lunch 2 0.208967 140 17.47 3.50 No Thur Lunch 2 0.200343 141 34.30 6.70 No Thur Lunch 6 0.195335 142 41.19 5.00 No Thur Lunch 5 0.121389 143 27.05 5.00 No Thur Lunch 6 0.184843 144 16.43 2.30 No Thur Lunch 2 0.139988 145 8.35 1.50 No Thur Lunch 2 0.179641 146 18.64 1.36 No Thur Lunch 3 0.072961 147 11.87 1.63 No Thur Lunch 2 0.137321 148 9.78 1.73 No Thur Lunch 2 0.176892 149 7.51 2.00 No Thur Lunch 2 0.266312 195 7.56 1.44 No Thur Lunch 2 0.190476 243 18.78 3.00 No Thur Dinner 2 0.159744), (('Thur', 'Yes'), total_bill tip smoker day time size tip_pct 80 19.44 3.00 Yes Thur Lunch 2 0.154321 83 32.68 5.00 Yes Thur Lunch 2 0.152999 138 16.00 2.00 Yes Thur Lunch 2 0.125000 191 19.81 4.19 Yes Thur Lunch 2 0.211509 192 28.44 2.56 Yes Thur Lunch 2 0.090014 193 15.48 2.02 Yes Thur Lunch 2 0.130491 194 16.58 4.00 Yes Thur Lunch 2 0.241255 196 10.34 2.00 Yes Thur Lunch 2 0.193424 197 43.11 5.00 Yes Thur Lunch 4 0.115982 198 13.00 2.00 Yes Thur Lunch 2 0.153846 199 13.51 2.00 Yes Thur Lunch 2 0.148038 200 18.71 4.00 Yes Thur Lunch 3 0.213789 201 12.74 2.01 Yes Thur Lunch 2 0.157771 202 13.00 2.00 Yes Thur Lunch 2 0.153846 203 16.40 2.50 Yes Thur Lunch 2 0.152439 204 20.53 4.00 Yes Thur Lunch 4 0.194837 205 16.47 3.23 Yes Thur Lunch 3 0.196114)]
f = lambda x: x.describe()
grouped.apply(f)
total_bill | tip | size | tip_pct | |||
---|---|---|---|---|---|---|
day | smoker | |||||
Fri | No | count | 4.000000 | 4.000000 | 4.00 | 4.000000 |
mean | 18.420000 | 2.812500 | 2.25 | 0.151650 | ||
std | 5.059282 | 0.898494 | 0.50 | 0.028123 | ||
min | 12.460000 | 1.500000 | 2.00 | 0.120385 | ||
25% | 15.100000 | 2.625000 | 2.00 | 0.137239 | ||
... | ... | ... | ... | ... | ... | ... |
Thur | Yes | min | 10.340000 | 2.000000 | 2.00 | 0.090014 |
25% | 13.510000 | 2.000000 | 2.00 | 0.148038 | ||
50% | 16.470000 | 2.560000 | 2.00 | 0.153846 | ||
75% | 19.810000 | 4.000000 | 2.00 | 0.194837 | ||
max | 43.110000 | 5.000000 | 4.00 | 0.241255 |
64 rows × 4 columns
10.3.1 그룹 색인 생략¶
group_keys=False¶
앞서 살펴본 예제들에서 반환된 객체는 원본 객체의 각 조각에 대한 색인과 그룹 키가 계층적 색인으로 사용됨
이런 결과는 groupby 메서드에 group_keys=False를 넘겨서 막을 수 있음
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 |
10.3.2 변위치 분석과 버킷 분석¶
cut¶
8장에서 본 내용을 떠올려보면 pandas의 cut과 qcut 메서드를 사용해 선택한 크기만큼 혹은 표본 변위치에 따라 데이터를 나눌 수 있었음
이 함수들을 groupby와 조합하면 데이터 묶음에 대해 변위치 분석이나 버킷 분석을 매우 쉽게 수행 가능
임의의 데이터 묶음을 cut을 이용해 등간격 구간으로 나누어보자
frame = pd.DataFrame({'data1':np.random.randn(1000),
'data2':np.random.rand(1000)})
frame
data1 | data2 | |
---|---|---|
0 | -1.545803 | 0.389293 |
1 | 0.325553 | 0.036452 |
2 | 0.754452 | 0.196032 |
3 | 1.200618 | 0.666071 |
4 | 0.049420 | 0.411390 |
... | ... | ... |
995 | 0.958495 | 0.551972 |
996 | -1.502701 | 0.915347 |
997 | 0.141496 | 0.657457 |
998 | 1.001334 | 0.781523 |
999 | -0.245511 | 0.792440 |
1000 rows × 2 columns
quartiles = pd.cut(frame.data1, 4)
quartiles
0 (-1.567, -0.00749] 1 (-1.567, -0.00749] 2 (-1.567, -0.00749] 3 (-1.567, -0.00749] 4 (-0.00749, 1.552] ... 995 (-1.567, -0.00749] 996 (-1.567, -0.00749] 997 (-0.00749, 1.552] 998 (-3.132, -1.567] 999 (-0.00749, 1.552] Name: data1, Length: 1000, dtype: category Categories (4, interval[float64, right]): [(-3.132, -1.567] < (-1.567, -0.00749] < (-0.00749, 1.552] < (1.552, 3.111]]
quartiles[:10]
0 (-1.567, -0.00749] 1 (-1.567, -0.00749] 2 (-1.567, -0.00749] 3 (-1.567, -0.00749] 4 (-0.00749, 1.552] 5 (-1.567, -0.00749] 6 (-1.567, -0.00749] 7 (-1.567, -0.00749] 8 (-0.00749, 1.552] 9 (-1.567, -0.00749] Name: data1, dtype: category Categories (4, interval[float64, right]): [(-3.132, -1.567] < (-1.567, -0.00749] < (-0.00749, 1.552] < (1.552, 3.111]]
cut에서 반환된 Categorical 객체는 바로 groupby로 넘길 수 있음
그러므로 data2 컬럼에 대한 몇 가지 통계를 다음과 같이 계산 가능
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 | ||||
(-3.132, -1.567] | 0.012302 | 0.996153 | 61.0 | 0.484891 |
(-1.567, -0.00749] | 0.001278 | 0.998848 | 423.0 | 0.508957 |
(-0.00749, 1.552] | 0.007817 | 0.997614 | 453.0 | 0.509484 |
(1.552, 3.111] | 0.002700 | 0.981879 | 63.0 | 0.466551 |
qcut¶
이는 등간격 버킷이었고, 표본 변위치에 기반해 크기가 같은 버킷을 계산하려면 qcut 사용
labels=False를 넘겨서 변위치 숫자 구하기
frame
data1 | data2 | |
---|---|---|
0 | -1.545803 | 0.389293 |
1 | 0.325553 | 0.036452 |
2 | 0.754452 | 0.196032 |
3 | 1.200618 | 0.666071 |
4 | 0.049420 | 0.411390 |
... | ... | ... |
995 | 0.958495 | 0.551972 |
996 | -1.502701 | 0.915347 |
997 | 0.141496 | 0.657457 |
998 | 1.001334 | 0.781523 |
999 | -0.245511 | 0.792440 |
1000 rows × 2 columns
#변위치 숫자 반환
grouping = pd.qcut(frame.data1, 10, labels=False)
grouped = frame.data2.groupby(grouping)
grouped.apply(get_stats).unstack()
min | max | count | mean | |
---|---|---|---|---|
data1 | ||||
0 | 0.000337 | 0.997166 | 100.0 | 0.525755 |
1 | 0.002551 | 0.999393 | 100.0 | 0.487861 |
2 | 0.011428 | 0.975284 | 100.0 | 0.498819 |
3 | 0.008830 | 0.998479 | 100.0 | 0.512392 |
4 | 0.000915 | 0.988763 | 100.0 | 0.514708 |
5 | 0.010643 | 0.995712 | 100.0 | 0.484741 |
6 | 0.008568 | 0.997925 | 100.0 | 0.535949 |
7 | 0.012733 | 0.975768 | 100.0 | 0.418350 |
8 | 0.026873 | 0.999498 | 100.0 | 0.491584 |
9 | 0.006303 | 0.998639 | 100.0 | 0.539004 |
10.3.3 예제: 그룹에 따른 값으로 결측치 채우기¶
fillna¶
누락된 데이터를 정리할 때면 어떤 경우에는 dropna를 사용해 데이터를 살펴보고 걸러냄
하지만 어떤 경우에는 누락된 값을 고정된 값이나 혹은 데이터로부터 도출된 어떤 값으로 채우고 싶을 때도 있음
이런 경우 fillna 메서드를 사용하는데, 누락된 값을 평균값으로 대체하는 예제를 살펴보자
s = pd.Series(np.random.randn(6))
s
0 0.208973 1 -1.318205 2 -0.112424 3 0.078798 4 1.239493 5 1.565277 dtype: float64
s[::2] = np.nan # s[::2]는 모든 범위에서 간격 2씩 떼고
s
0 NaN 1 -1.318205 2 NaN 3 0.078798 4 NaN 5 1.565277 dtype: float64
s.fillna(s.mean())
0 0.108623 1 -1.318205 2 0.108623 3 0.078798 4 0.108623 5 1.565277 dtype: float64
그룹별로 채워 넣고 싶은 값이 다른 경우
- 데이터를 그룹으로 나누고 apply 함수를 사용해 각 그룹에 대해 fillna 적용
여기서 사용된 데이터는 동부와 서부로 나눈 미국의 지역에 대한 데이터
states = ['Ohio', 'New York', 'Vermont', 'Florida',
'Oregon', 'Nevada', 'California', 'Idaho']
group_key = ['East'] * 4 + ['West'] * 4
group_key
['East', 'East', 'East', 'East', 'West', 'West', 'West', 'West']
data = pd.Series(np.random.randn(8), index=states)
data
Ohio 0.444533 New York -2.374675 Vermont -1.623302 Florida 1.504970 Oregon -2.013114 Nevada -0.852090 California -1.421805 Idaho -2.147316 dtype: float64
['East']*4는 ['East'] 리스트 안에 있는 네 벌의 원소를 이어붙임
리스트를 더하면 각 리스트를 이어붙일 수 있음
데이터에서 몇몇 값을 결측치로 만들어보자
data[['Vermont', 'Nevada', 'Idaho']] = np.nan
data
Ohio 0.444533 New York -2.374675 Vermont NaN Florida 1.504970 Oregon -2.013114 Nevada NaN California -1.421805 Idaho NaN dtype: float64
data.groupby(group_key).mean()
East -0.141724 West -1.717460 dtype: float64
다음과 같이 누락된 값을 그룹의 평균값으로 채울 수 있음
fill_mean = lambda g:g.fillna(g.mean())
data.groupby(group_key).apply(fill_mean)
C:\Users\user\AppData\Local\Temp\ipykernel_14620\763740747.py:1: FutureWarning: Not prepending group keys to the result index of transform-like apply. In the future, the group keys will be included in the index, regardless of whether the applied function returns a like-indexed object. To preserve the previous behavior, use >>> .groupby(..., group_keys=False) To adopt the future behavior and silence this warning, use >>> .groupby(..., group_keys=True) data.groupby(group_key).apply(fill_mean)
Ohio 0.444533 New York -2.374675 Vermont -0.141724 Florida 1.504970 Oregon -2.013114 Nevada -1.717460 California -1.421805 Idaho -1.717460 dtype: float64
아니면 그룹에 따라 미리 정의된 다른 값을 채워 넣어야 할 경우도 있음
각 그룹은 내부적으로 name이라는 속성을 가지므로 이를 이용하자
fill_values = {'East':0.5, 'West':-1}
fill_func = lambda g: g.fillna(fill_values[g.name])
data.groupby(group_key).apply(fill_func)
C:\Users\user\AppData\Local\Temp\ipykernel_14620\2085919508.py:1: FutureWarning: Not prepending group keys to the result index of transform-like apply. In the future, the group keys will be included in the index, regardless of whether the applied function returns a like-indexed object. To preserve the previous behavior, use >>> .groupby(..., group_keys=False) To adopt the future behavior and silence this warning, use >>> .groupby(..., group_keys=True) data.groupby(group_key).apply(fill_func)
Ohio 0.444533 New York -2.374675 Vermont 0.500000 Florida 1.504970 Oregon -2.013114 Nevada -1.000000 California -1.421805 Idaho -1.000000 dtype: float64
10.4 피벗테이블과 교차일람표¶
pivot_table¶
피벗테이블은 데이터를 하나 이상의 키로 수집해서 어떤 키는 로우에, 어떤 키는 컬럼에 나열해서 데이터 정렬
pivot_table은 *마진*이라고 하는 부분합을 추가할 수 있는 기능 제공
팁 데이터로 돌아가 요일(day)과 흡연자(smoker) 집단에서 평균(pivot_table의 기본 연산)을 구하자
tips
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 |
... | ... | ... | ... | ... | ... | ... | ... |
239 | 29.03 | 5.92 | No | Sat | Dinner | 3 | 0.203927 |
240 | 27.18 | 2.00 | Yes | Sat | Dinner | 2 | 0.073584 |
241 | 22.67 | 2.00 | Yes | Sat | Dinner | 2 | 0.088222 |
242 | 17.82 | 1.75 | No | Sat | Dinner | 2 | 0.098204 |
243 | 18.78 | 3.00 | No | Thur | Dinner | 2 | 0.159744 |
244 rows × 7 columns
tips.pivot_table(index=['day', 'smoker'])
C:\Users\user\AppData\Local\Temp\ipykernel_14620\2966571272.py:1: FutureWarning: pivot_table dropped a column because it failed to aggregate. This behavior is deprecated and will raise in a future version of pandas. Select only the columns that can be aggregated. tips.pivot_table(index=['day', 'smoker'])
size | tip | tip_pct | total_bill | ||
---|---|---|---|---|---|
day | smoker | ||||
Fri | No | 2.250000 | 2.812500 | 0.151650 | 18.420000 |
Yes | 2.066667 | 2.714000 | 0.174783 | 16.813333 | |
Sat | No | 2.555556 | 3.102889 | 0.158048 | 19.661778 |
Yes | 2.476190 | 2.875476 | 0.147906 | 21.276667 | |
Sun | No | 2.929825 | 3.167895 | 0.160113 | 20.506667 |
Yes | 2.578947 | 3.516842 | 0.187250 | 24.120000 | |
Thur | No | 2.488889 | 2.673778 | 0.160298 | 17.113111 |
Yes | 2.352941 | 3.030000 | 0.163863 | 19.190588 |
이는 groupby를 사용해 쉽게 구할 수 있는데, 이제 tip_pct와 size에 대해서만 집계를 하고 날짜(time)별로 그룹지어보자
이를 위해 day 로우와 smoker 컬럼을 추가함
tips.pivot_table(['tip_pct', 'size'], index=['time', 'day'],
columns='smoker')
size | tip_pct | ||||
---|---|---|---|---|---|
smoker | No | Yes | No | Yes | |
time | day | ||||
Dinner | Fri | 2.000000 | 2.222222 | 0.139622 | 0.165347 |
Sat | 2.555556 | 2.476190 | 0.158048 | 0.147906 | |
Sun | 2.929825 | 2.578947 | 0.160113 | 0.187250 | |
Thur | 2.000000 | NaN | 0.159744 | NaN | |
Lunch | Fri | 3.000000 | 1.833333 | 0.187735 | 0.188937 |
Thur | 2.500000 | 2.352941 | 0.160311 | 0.163863 |
margins_True¶
이 테이블은 marins_True를 넘겨서 부분합을 포함하도록 확장할 수 있는데,
그렇게 하면 All컬럼과 All 로우가 추가되어 단일 줄 안에서 그룹 통계 얻기 가능
tips.pivot_table(['tip_pct', 'size'], index=['time', 'day'],
columns = 'smoker', margins=True)
size | tip_pct | ||||||
---|---|---|---|---|---|---|---|
smoker | No | Yes | All | No | Yes | All | |
time | day | ||||||
Dinner | Fri | 2.000000 | 2.222222 | 2.166667 | 0.139622 | 0.165347 | 0.158916 |
Sat | 2.555556 | 2.476190 | 2.517241 | 0.158048 | 0.147906 | 0.153152 | |
Sun | 2.929825 | 2.578947 | 2.842105 | 0.160113 | 0.187250 | 0.166897 | |
Thur | 2.000000 | NaN | 2.000000 | 0.159744 | NaN | 0.159744 | |
Lunch | Fri | 3.000000 | 1.833333 | 2.000000 | 0.187735 | 0.188937 | 0.188765 |
Thur | 2.500000 | 2.352941 | 2.459016 | 0.160311 | 0.163863 | 0.161301 | |
All | 2.668874 | 2.408602 | 2.569672 | 0.159328 | 0.163196 | 0.160803 |
여기서 All 값은 흡연자와 비흡연자를 구분하지 않은 평균값(All 컬럼)이거나
로우에서 두 단계를 묶은 그룹의 평균값(All로우)
aggfunc¶
다른 집계함수를 사용하려면 그냥 aggfunc로 넘기면 되는데,
예를 들어 'count'나 len 함수는 그룹 크기의 교차일람표(총 개수나 빈도) 반환
tips.pivot_table('tip_pct', index=['time', 'smoker'], columns='day',
aggfunc=len, margins=True)
day | Fri | Sat | Sun | Thur | All | |
---|---|---|---|---|---|---|
time | smoker | |||||
Dinner | No | 3.0 | 45.0 | 57.0 | 1.0 | 106 |
Yes | 9.0 | 42.0 | 19.0 | NaN | 70 | |
Lunch | No | 1.0 | NaN | NaN | 44.0 | 45 |
Yes | 6.0 | NaN | NaN | 17.0 | 23 | |
All | 19.0 | 87.0 | 76.0 | 62.0 | 244 |
만약 어떤 조합이 비어있다면(혹은 NA 값) fill_value를 넘길 수도 있다
tips.pivot_table('tip_pct', index=['time', 'size', 'smoker'],
columns='day', aggfunc='mean', fill_value=0)
day | Fri | Sat | Sun | Thur | ||
---|---|---|---|---|---|---|
time | size | smoker | ||||
Dinner | 1 | No | 0.000000 | 0.137931 | 0.000000 | 0.000000 |
Yes | 0.000000 | 0.325733 | 0.000000 | 0.000000 | ||
2 | No | 0.139622 | 0.162705 | 0.168859 | 0.159744 | |
Yes | 0.171297 | 0.148668 | 0.207893 | 0.000000 | ||
3 | No | 0.000000 | 0.154661 | 0.152663 | 0.000000 | |
Yes | 0.000000 | 0.144995 | 0.152660 | 0.000000 | ||
4 | No | 0.000000 | 0.150096 | 0.148143 | 0.000000 | |
Yes | 0.117750 | 0.124515 | 0.193370 | 0.000000 | ||
5 | No | 0.000000 | 0.000000 | 0.206928 | 0.000000 | |
Yes | 0.000000 | 0.106572 | 0.065660 | 0.000000 | ||
6 | No | 0.000000 | 0.000000 | 0.103799 | 0.000000 | |
Lunch | 1 | No | 0.000000 | 0.000000 | 0.000000 | 0.181728 |
Yes | 0.223776 | 0.000000 | 0.000000 | 0.000000 | ||
2 | No | 0.000000 | 0.000000 | 0.000000 | 0.166005 | |
Yes | 0.181969 | 0.000000 | 0.000000 | 0.158843 | ||
3 | No | 0.187735 | 0.000000 | 0.000000 | 0.084246 | |
Yes | 0.000000 | 0.000000 | 0.000000 | 0.204952 | ||
4 | No | 0.000000 | 0.000000 | 0.000000 | 0.138919 | |
Yes | 0.000000 | 0.000000 | 0.000000 | 0.155410 | ||
5 | No | 0.000000 | 0.000000 | 0.000000 | 0.121389 | |
6 | No | 0.000000 | 0.000000 | 0.000000 | 0.173706 |
pivot_table 옵션¶
- 420쪽
10.4.1 교차일람표¶
교차일람표(또는 *교차표*)는 그룹 빈도 계산을 위한 피벗테이블의 특수한 경우
data
Ohio 0.444533 New York -2.374675 Vermont NaN Florida 1.504970 Oregon -2.013114 Nevada NaN California -1.421805 Idaho NaN dtype: float64
data = pd.DataFrame({'Sample':np.arange(1,11),
'Nationality':['USA', 'Japan', 'USA','Japan', 'Japan', 'Japan', 'USA', 'USA', 'Japan', 'USA'],
'Handedness':['Right-handed', 'Left-handed', 'Right-handed', 'Right-handed', 'Left-handed', 'Right-handed', 'Right-handed', 'Left-handed', 'Right-handed', 'Right-handed']})
data
Sample | Nationality | Handedness | |
---|---|---|---|
0 | 1 | USA | Right-handed |
1 | 2 | Japan | Left-handed |
2 | 3 | USA | Right-handed |
3 | 4 | Japan | Right-handed |
4 | 5 | Japan | Left-handed |
5 | 6 | Japan | Right-handed |
6 | 7 | USA | Right-handed |
7 | 8 | USA | Left-handed |
8 | 9 | Japan | Right-handed |
9 | 10 | USA | Right-handed |
pandas.crosstab¶
설문 분석의 일부로서 이 데이터를 국적(nationality)과 잘 쓰는 손(handedness)에 따라 요약해보자
이를 위해 pivot_table 메서드를 사용가능하지만 pandas.crosstab 함수가 훨씬 더 편리
pd.crosstab(data.Nationality, data.Handedness, margins=True)
Handedness | Left-handed | Right-handed | All |
---|---|---|---|
Nationality | |||
Japan | 2 | 3 | 5 |
USA | 1 | 4 | 5 |
All | 3 | 7 | 10 |
crosstab 함수의 처음 두 인자는 배열이나 Series 혹은 배열의 리스트가 될 수 있다
팁 데이터에 대해 교차표를 구해보자
pd.crosstab([tips.time, tips.day], tips.smoker, margins=True)
smoker | No | Yes | All | |
---|---|---|---|---|
time | day | |||
Dinner | Fri | 3 | 9 | 12 |
Sat | 45 | 42 | 87 | |
Sun | 57 | 19 | 76 | |
Thur | 1 | 0 | 1 | |
Lunch | Fri | 1 | 6 | 7 |
Thur | 44 | 17 | 61 | |
All | 151 | 93 | 244 |
'Python, Jupyter 🐍 > [python]파이썬 데이터분석' 카테고리의 다른 글
지도에 서울소재대학 위치 표시하기 (0) | 2023.04.18 |
---|---|
9장 (0) | 2023.04.18 |
7장 (0) | 2023.04.17 |
[오류] 'jupyter'은(는) 내부 또는 외부 명령, 실행할 수 있는 프로그램, 또는배치 파일이 아닙니다. (0) | 2023.04.09 |
[오류] TypeError: concat() got an unexpected keyword argument 'join_axes' (0) | 2023.04.07 |