- Published on
Pandas에서 Aggregate하기
- Authors

- Name
- Eunsu Kim
- @eunsukimme
이번 포스팅에서는 Pandas 의 Aggregates에 대해서 알아봅시다. Aggregates는 숫자로 구성된 특정 그룹을 설명할 수 있는 단일 숫자를 만들어내는 강력한 방법입니다. 일반적으로 평균, 표준편차, 중간값 등이 자주 사용됩니다.
Calculating Column Statistics
저번 포스팅에서는 apply 함수를 활용하여 특정 column 의 각 value 에 대해 연산을 수행하는 방법에 대해서 알아보았습니다. 이번에는 모든 value 에 대해서 연산을 수행하는 방법에 대해서 알아봅시다.
먼저 손님들의 정보를 저장한 customers란 DataFrame이 있다고 가정해봅시다. 만약 손님들의 나이의 중간값을 구하고자 한다면 다음과 같이 코드를 작성할 수 있습니다.
print(customers.age)
>> [23, 25, 31, 35, 35, 46, 62]
print(customers.age.median())
>> 35 # 중간값을 반환합니다.
이번에는 물류 배송 정보를 저장한 shipments란 DataFrame이 있다고 가정해봅시다. 만약 특정 배송지들이 각각 얼마나 배송되었는지를 구하고자 한다면 다음과 같이 코드를 작성할 수 있습니다.
print(shipments.state)
>> ['CA', 'CA', 'CA', 'CA', 'NY', 'NY', 'NJ', 'NJ', 'NJ', 'NJ', 'NJ', 'NJ', 'NJ']
print(shipments.state.nunique())
>> 3 # unique한 값의 수를 반환합니다.
이번에는 옷가게에서 T-shirt 정보를 저장하는 inventory 란 DataFrame이 있다고 가정해봅시다. T-shirt 의 색깔로 어떤 것들이 있는지를 구하고자 한다면 다음과 같이 코드를 작성할 수 있습니다.
print(inventory.color)
>> ['blue', 'blue', 'blue', 'blue', 'blue', 'green', 'green', 'orange', 'orange', 'orange']
print(inventory.color.unique())
>> ['blue', 'green', 'orange'] # unique한 값들을 반환합니다.
이러한 syntax 를 일반화하면 다음과 같습니다.
df.column_name.command()
자주 쓰이는 command 를 정리한 표는 아래와 같습니다.
| Command | Description |
|---|---|
mean | 특정 column 의 모든 value 의 평균값 |
std | 표준편차 |
median | 중간값 |
max | 특정 column 내 최대값 |
min | 특정 column 내 최소값 |
count | 특정 column 내 value 의 개수 |
nunique | 특정 column 내 unique 한 value 의 개수 |
unique | 특정 column 내 unique 한 value 의 배열 |
Calculating Aggregate Functions
많은 데이터를 보유하게 된다면, 데이터의 특정 부분에 대해서 aggregates 연산을 수행하고 싶을 때가 종종 있습니다. 예를 들어 다음과 같은 DataFrame이 있다고 가정해봅시다.
| student | assignment_name | grade |
|---|---|---|
| Amy | Assignment 1 | 75 |
| Amy | Assignment 2 | 35 |
| Bob | Assignment 1 | 99 |
| Bob | Assignment 2 | 35 |
| … |
각 학생들의 평균 grade 를 계산하고 싶다고 해봅시다. 이를 반복문으로도 실행할 수 있지만, Pandas 의 groupby 함수를 활용하면 매우 쉽게 연산이 가능합니다.
grades = df.groupby('student').grade.mean()
print(grades)
위 코드의 실행 결과는 다음과 같습니다.
| student | grade |
|---|---|
| Amy | 80 |
| Bob | 90 |
| Chris | 75 |
| … |
.groupby 함수의 일반적인 syntax 는 다음과 같습니다.
df.groupby('column1').column2.measurement()
column1은 그룹으로 만들고자 하는 column 입니다.column2는 measurement 를 수행하고자 하는 column 입니다(여기서는grade가 됩니다).measurement는 적용하고자 하는 함수입니다(여기서는mean입니다).
groupby 함수는 결과값으로 DataFrame이 아닌 Series를 반환합니다. 이 때 반환된 Series의 index 는 groupby 함수에 주어진 column 의 value 이며, name 속성은 measurement 가 수행된 column 의 name 입니다.
그런데 column 의 value 를 index 로 사용하는 것보단 정수값이 주어지는 것이 일반적으로 보기 더 좋습니다. 이를 위해 reset_index() 함수를 사용할 수 있는데, 결과적으로 Series를 DataFrame으로 변환하고 기존의 index 를 column 으로 만들어버립니다.
이러한 장점으로 인해 일반적으로 groupby 함수 뒤에는 reset_index 함수가 뒤따라옵니다.
df.groupby('column1').column2.measurement()
.reset_index()
이해를 돕기 위해 다음과 같이 찻집의 Tea 정보를 저장하는 DataFrame이 있다고 가정해봅시다.
| id | tea | category | caffeine | price |
|---|---|---|---|---|
| 0 | earl grey | black | 38 | 3 |
| 1 | english breakfast | black | 41 | 3 |
| 2 | irish breakfast | black | 37 | 2.5 |
| 3 | jasmine | green | 23 | 4.5 |
| 4 | matcha | green | 48 | 5 |
| 5 | camomile | herbal | 0 | 3 |
| … |
Tea 가 category 별로 얼마나 있는지 확인해보고자 한다면 다음과 같이 코드를 작성할 수 있습니다.
teas_counts = teas.groupby('category').id.count().reset_index()
print(teas_counts)
위 코드의 실행 결과는 다음과 같습니다.
| category | id | |
|---|---|---|
| 0 | black | 3 |
| 1 | green | 4 |
| 2 | herbal | 8 |
| 3 | white | 2 |
| … |
reset_index 를 호출함으로써 기존의 index 인 category 가 새로운 column 으로 형성된 것을 확인할 수 있습니다. 한 발짝만 더 나가자면, 각 category 별 tea 의 수를 나타내는 컬럼의 name 이 id 인데, 보기 좋게 하기 위해 column 이름을 변경해 줄 수 있습니다.
teas_counts = teas_counts.rename(columns={"id": "counts"})
이제 DataFrame은 다음과 같습니다.
| category | counts | |
|---|---|---|
| 0 | black | 3 |
| 1 | green | 4 |
| 2 | herbal | 8 |
| 3 | white | 2 |
| … |
Apply with Lambda
가끔은 mean 이나 count 말고 더 복잡한 연산을 필요로 할 때가 있습니다. 이러한 경우, apply 함수를 사용하여 파라미터로 lambda 함수를 제공할 수 있습니다. Column 연산을 수행할때 처럼 말이죠. 한가지 명심해야 할 것은 Aggregates 단계의 apply 함수의 파라미터로 주어지는 lambda 함수의 input 은 column 의 값들로 구성된 list 란 것입니다.
이해를 돕기 위해 어떤 회사의 employee 들의 id, 이름, 임금, 직종을 나타내는 다음과 같은 DataFrame이 있다고 가정해봅시다.
| id | name | wage | category |
|---|---|---|---|
| 10131 | Sarah Carney | 39 | product |
| 14189 | Heather Carey | 17 | design |
| 15004 | Gary Mercado | 33 | marketing |
| 11204 | Cora Copaz | 27 | design |
| … |
만약 각 catogory 별로 75th percentile(75%의 employee 보다 임금이 높고 25%의 employee 보다 임금이 낮은 지점)의 임금을 구하고자 한다면 다음과 같이 코드를 작성할 수 있습니다.
# np.percentile 함수는 입력으로 주어진 list에서 특정 지점의 percentile을 계산합니다.
high_earners = df.groupby('category').wage.apply(lambda wages: np.percentile(wages, 75)).reset_index()
계산된 high_earners 는 다음과 같이 됩니다.
| category | wage | |
|---|---|---|
| 0 | design | 23 |
| 1 | marketing | 35 |
| 2 | product | 48 |
| … |
Multiple Groupby
가끔은 여러 column 을 group 하는 경우도 생기게 됩니다. 이는 간단히 groupby 함수의 파라미터로 column 의 name 을 list 로 전달해주면 됩니다. 예를 들어 레스토랑 체인점의 판매 기록을 저장하는 다음과 같은 DataFrame이 있다고 생각해봅시다.
| Location | Date | Day of Week | Total Sales |
|---|---|---|---|
| West Village | February 1 | W | 400 |
| West Village | February 2 | Th | 450 |
| Chelsea | February 1 | W | 375 |
| Chelsea | February 2 | Th | 390 |
| ... |
만약 각 Location 의 Day of Week 별 Total Sales 의 평균을 계산하고 싶다면 다음과 같이 코드를 작성할 수 있습니다.
df.groupby(['Location', 'Day of Week'])['Total Sales'].mean().reset_index()
결과는 다음과 같게 됩니다.
| Location | Day of Week | Total Sales |
|---|---|---|
| Chelsea | M | 402.50 |
| Chelsea | Tu | 422.75 |
| Chelsea | W | 452.00 |
| … | ||
| West Village | M | 390 |
| West Village | Tu | 400 |
| … |
Pivot Tables
groupby 를 수행하고 난 뒤, 가끔 데이터를 저장하는 방식을 변경하고 싶을수도 있습니다. 바로 이전의 레스토랑 DataFrame의 경우, 다음과 같이 표현할 수 있다면 더 가독성이 높아질 것입니다.
| Location | M | Tu | W | Th | F | Sa | Su |
|---|---|---|---|---|---|---|---|
| Chelsea | 400 | 390 | 250 | 275 | 300 | 150 | 175 |
| West Village | 300 | 310 | 350 | 400 | 390 | 250 | 200 |
| … |
이렇게 테이블을 reorganizing 하는 방법을 pivoting 이라고 합니다. 그리하여 새롭게 생성된 테이블을 pivot table 이라고 부릅니다. Pandas 에서는 다음과 같이 pivot 을 수행할 수 있습니다.
df.pivot(columns='ColumnToPivot',
index='ColumnToBeRows',
values='ColumnToBeValues')
레스토랑 DataFrame의 경우 다음과 같이 코드를 작성할 수 있습니다.
# 먼저 groupby 연산을 수행합니다.
unpivoted = df.groupby(['Location', 'Day of Week'])['Total Sales'].mean().reset_index()
# 그런 다음 pivot table을 만듭니다.
pivoted = unpivoted.pivot(
columns='Day of Week',
index='Location',
values='Total Sales')
pivot 함수는 실행 결과로 DataFrame을 반환합니다. 이때 indexing 이 이상하게 만들어지는 경향이 있어서, 일반적으로 pivot 뒤에도 reset_index 를 호출해줍니다.
Review
이번 포스팅에서는 Pandas 의 Aggregates에 대한 많은 내용을 다루어보았습니다. 그 내용을 정리해보면 다음과 같습니다:
- How to perform aggregate statistics over individual rows with the same value using
groupby. - How to rearrange a DataFrame into a pivot table, a great way to compare data across two dimensions.
Pandas 는 공부할수록 재미있는 라이브러리인 것 같습니다. 얼른 실생활에 널려있는 데이터를 분석하고 싶어지지 않나요?😄