import pandas as pd
import numpy as np08wk-2: Pandas – groupby, 데이터프레임의 결합
pandas
1. 강의영상
2. Imports
3. groupby
A. DataFrameGroupBy
- groupby + agg 의 복습
df = pd.DataFrame({'department':['A','A','B','B'], 'gender':['male','female','male','female'],'count':[1,2,3,1]})
df| department | gender | count | |
|---|---|---|---|
| 0 | A | male | 1 |
| 1 | A | female | 2 |
| 2 | B | male | 3 |
| 3 | B | female | 1 |
df.groupby('department').agg({'count':'sum'})| count | |
|---|---|
| department | |
| A | 3 |
| B | 4 |
- 의문: 위의 코드에서 df.groupby('department')는 어떤 object일까?
g = df.groupby('department')
g<pandas.core.groupby.generic.DataFrameGroupBy object at 0x7f3d9461c9d0>
set(dir(g)) & {'__iter__'} # g는 반복문을 돌리기 유리하게 설계되어 있음{'__iter__'}
list(g) # for문의 반복인자는 ('A',sub-dataframe)와 같은 형식의 tuple임[('A',
department gender count
0 A male 1
1 A female 2),
('B',
department gender count
2 B male 3
3 B female 1)]
오브젝트 g는
- sub-dataframe 이 모여있는 묶음체이다.
- 반복문을 돌리기에 용이하도록 고안되어있다. (이때 각 반복인자는
(묵음기준,sub-dataframe)의 튜플로 이루어져 있음)
- 제가 이해하는 방식
dct = {k:df for k,df in g}
dct {'A': department gender count
0 A male 1
1 A female 2,
'B': department gender count
2 B male 3
3 B female 1}
display(dct['A'])
display(dct['B'])| department | gender | count | |
|---|---|---|---|
| 0 | A | male | 1 |
| 1 | A | female | 2 |
| department | gender | count | |
|---|---|---|---|
| 2 | B | male | 3 |
| 3 | B | female | 1 |
B. g를 이용하는 방법
# 예시1: g를 이용하여 원래의 df를 복원하라.
df = pd.DataFrame({'department':['A','A','B','B'], 'gender':['male','female','male','female'],'count':[1,2,3,1]})
g = df.groupby('department')(풀이)
pd.concat([df for _,df in g])| department | gender | count | |
|---|---|---|---|
| 0 | A | male | 1 |
| 1 | A | female | 2 |
| 2 | B | male | 3 |
| 3 | B | female | 1 |
#
# 예시2: g를 이용하여 아래와 동일한 기능을 하는 코드를 작성하라. (agg 함수 사용금지)
df = pd.DataFrame({'department':['A','A','B','B'], 'gender':['male','female','male','female'],'count':[1,2,3,1]})
df.groupby('department').agg({'count':'sum'})| count | |
|---|---|
| department | |
| A | 3 |
| B | 4 |
(풀이)
g = df.groupby('department')
g<pandas.core.groupby.generic.DataFrameGroupBy object at 0x7f3d9461fdc0>
pd.DataFrame(pd.Series({k:df['count'].sum() for k,df in g}))| 0 | |
|---|---|
| A | 3 |
| B | 4 |
#
# 예시3: 아래는 데이터프레임이 있다고 치자. 이 데이터프레임을 class 를 기준으로 그룹핑하여 sub-dataframe을 만들고 score가 높은 순서로 정렬하는 코드를 작성하라.
df = pd.DataFrame({'class':['A']*5+['B']*5, 'id':[0,1,2,3,4]*2, 'score':[60,20,40,60,90,20,30,90,95,95]})
df| class | id | score | |
|---|---|---|---|
| 0 | A | 0 | 60 |
| 1 | A | 1 | 20 |
| 2 | A | 2 | 40 |
| 3 | A | 3 | 60 |
| 4 | A | 4 | 90 |
| 5 | B | 0 | 20 |
| 6 | B | 1 | 30 |
| 7 | B | 2 | 90 |
| 8 | B | 3 | 95 |
| 9 | B | 4 | 95 |
(풀이)
pd.concat([df.sort_values('score',ascending=False) for k,df in df.groupby('class')])| class | id | score | |
|---|---|---|---|
| 4 | A | 4 | 90 |
| 0 | A | 0 | 60 |
| 3 | A | 3 | 60 |
| 2 | A | 2 | 40 |
| 1 | A | 1 | 20 |
| 8 | B | 3 | 95 |
| 9 | B | 4 | 95 |
| 7 | B | 2 | 90 |
| 6 | B | 1 | 30 |
| 5 | B | 0 | 20 |
#
4. concat
pass 5. merge
A. 가장 빈번하게 사용하는 상황
# 예시1 – big dataframe에 groupby+agg를 사용하여 small dataframe이 생긴경우
big = pd.DataFrame({'department':['A','A','B','B'], 'gender':['male','female','male','female'],'count':[1,2,3,1]})
small = pd.DataFrame({'department':['A','B'], 'count_sum':[3,4]})display("big",big)
display("small",small)'big'
| department | gender | count | |
|---|---|---|---|
| 0 | A | male | 1 |
| 1 | A | female | 2 |
| 2 | B | male | 3 |
| 3 | B | female | 1 |
'small'
| department | count_sum | |
|---|---|---|
| 0 | A | 3 |
| 1 | B | 4 |
- 정보를 종합하기 위해서는 아래와 같이 하면 된다.
pd.merge(big,small)
big.merge(small)
#---#
pd.merge(small,big)
small.merge(big)| department | count_sum | gender | count | |
|---|---|---|---|---|
| 0 | A | 3 | male | 1 |
| 1 | A | 3 | female | 2 |
| 2 | B | 4 | male | 3 |
| 3 | B | 4 | female | 1 |
- merge에 대한 약간의 개념
- 상황: 두 데이터프레임은 특정한 IndexLabel에 대하여 서로 다른 정보를 각각 정리한 상황
- 원리: (1) 연결고리파악: 두 데이터프레임에서 공통인 열(IndexLabel)을 찾는다. (2) 병합: 연결고리를 기준으로 데이터의 정보를 병합한다.
이 예시의 경우
- IndexLabel = 연결고리 = 공통의열 =
department - 서로다른정보들: 이 예제에서 big은
department에 대한gender와count를 정리하고 있음. 그리고 small은department에 대한count_sum을 정리하고 있음. 이는 서로 다른 정보임.
배울게 좀 더 남음: 사실 아래는 같은 코드이다.
pd.merge(big,small)
pd.merge(big,small, on='department')| department | gender | count | count_sum | |
|---|---|---|---|---|
| 0 | A | male | 1 | 3 |
| 1 | A | female | 2 | 3 |
| 2 | B | male | 3 | 4 |
| 3 | B | female | 1 | 4 |
#
B. 여러가지 파라메터
# 예시1 – on
big = pd.DataFrame({'department':['A','A','B','B'], 'gender':['male','female','male','female'],'count':[1,2,3,1]})
small = big.groupby('department').agg({'count':'sum'}).reset_index()
display("big",big)
display("small",small)'big'
| department | gender | count | |
|---|---|---|---|
| 0 | A | male | 1 |
| 1 | A | female | 2 |
| 2 | B | male | 3 |
| 3 | B | female | 1 |
'small'
| department | count | |
|---|---|---|
| 0 | A | 3 |
| 1 | B | 4 |
- 잘못된 코드
pd.merge(big,small)| department | gender | count |
|---|
- 올바른 코드
pd.merge(big,small,on='department')| department | gender | count_x | count_y | |
|---|---|---|---|---|
| 0 | A | male | 1 | 3 |
| 1 | A | female | 2 | 3 |
| 2 | B | male | 3 | 4 |
| 3 | B | female | 1 | 4 |
* 더(?) 올바른 코드 – 좀 더 제 스타일의 코드
pd.merge(big,small.rename({'count':'count_sum'},axis=1))| department | gender | count | count_sum | |
|---|---|---|---|---|
| 0 | A | male | 1 | 3 |
| 1 | A | female | 2 | 3 |
| 2 | B | male | 3 | 4 |
| 3 | B | female | 1 | 4 |
배울게 좀 더 남음: 사실 아래는 같은 코드이다.
pd.merge(big,small,on='department')
pd.merge(big,small,left_on='department', right_on='department')| department | gender | count_x | count_y | |
|---|---|---|---|---|
| 0 | A | male | 1 | 3 |
| 1 | A | female | 2 | 3 |
| 2 | B | male | 3 | 4 |
| 3 | B | female | 1 | 4 |
#
# 예시2 – left_on, right_on
big = pd.DataFrame({'department':['A','A','B','B'], 'gender':['male','female','male','female'],'count':[1,2,3,1]})
small = pd.DataFrame({'dept':['A','B'], 'count':[3,4]})
display("big",big)
display("small",small)'big'
| department | gender | count | |
|---|---|---|---|
| 0 | A | male | 1 |
| 1 | A | female | 2 |
| 2 | B | male | 3 |
| 3 | B | female | 1 |
'small'
| dept | count | |
|---|---|---|
| 0 | A | 3 |
| 1 | B | 4 |
- 공통의 열이 오히려 ‘count’ 이고 서로 다른 정보들은 ‘gender’,‘department’,‘dept’ 이다.
- 잘못된 코드
pd.merge(big,small)| department | gender | count | dept | |
|---|---|---|---|---|
| 0 | B | male | 3 | A |
- 올바른 코드
pd.merge(big,small,left_on='department',right_on='dept')| department | gender | count_x | dept | count_y | |
|---|---|---|---|---|---|
| 0 | A | male | 1 | A | 3 |
| 1 | A | female | 2 | A | 3 |
| 2 | B | male | 3 | B | 4 |
| 3 | B | female | 1 | B | 4 |
* 좀 더 제 스타일의 코드
pd.merge(big,small.set_axis(['department','count_sum'],axis=1))| department | gender | count | count_sum | |
|---|---|---|---|---|
| 0 | A | male | 1 | 3 |
| 1 | A | female | 2 | 3 |
| 2 | B | male | 3 | 4 |
| 3 | B | female | 1 | 4 |
#
# 예제3: how
df1 = pd.DataFrame({
'dept':['통계','수학','과학','IAB'],
'count':[20,30,25,50]
})
df2 = pd.DataFrame({
'dept':['통계','수학','과학','신설학과'],
'desc':['통계학과는...','수학과는...','과학학과는...','이 학과는 내년에 신설될 예정이고...']
})
display("df1",df1)
display("df2",df2)'df1'
| dept | count | |
|---|---|---|
| 0 | 통계 | 20 |
| 1 | 수학 | 30 |
| 2 | 과학 | 25 |
| 3 | IAB | 50 |
'df2'
| dept | desc | |
|---|---|---|
| 0 | 통계 | 통계학과는... |
| 1 | 수학 | 수학과는... |
| 2 | 과학 | 과학학과는... |
| 3 | 신설학과 | 이 학과는 내년에 신설될 예정이고... |
- 공통의열인
dept와 서로다른 정보인count,desc들의 이름이 예쁘게 정리되어 있어on,left_on,right_on와 같은 파라메터를 사용할 필요가 없다.
pd.merge(df1,df2) # IAB, 신설학과는 사라짐| dept | count | desc | |
|---|---|---|---|
| 0 | 통계 | 20 | 통계학과는... |
| 1 | 수학 | 30 | 수학과는... |
| 2 | 과학 | 25 | 과학학과는... |
- 상황: IAB 학과는 df1에만, 신설학과는 df2에만 존재한다. \(\to\) IAB와 신설학과를 처리하는 방식에 따라서 4가지 경우로 나누어진다.
# 경우1: 두 학과 모두 제거 = 두 데이터프레임의 공통만 취함
pd.merge(df1,df2)
pd.merge(df1,df2,how='inner')| dept | count | desc | |
|---|---|---|---|
| 0 | 통계 | 20 | 통계학과는... |
| 1 | 수학 | 30 | 수학과는... |
| 2 | 과학 | 25 | 과학학과는... |
# 경우2: IAB만 살림 = 왼쪽 데이터프레임에 포함된 모든 학과는 살림
pd.merge(df1,df2)
pd.merge(df1,df2,how='left')| dept | count | desc | |
|---|---|---|---|
| 0 | 통계 | 20 | 통계학과는... |
| 1 | 수학 | 30 | 수학과는... |
| 2 | 과학 | 25 | 과학학과는... |
| 3 | IAB | 50 | NaN |
# 경우3: 신설학과만 살람 = 오른쪽 데이터프레임에 포함된 모든학과를 살람
pd.merge(df1,df2)
pd.merge(df1,df2,how='right')| dept | count | desc | |
|---|---|---|---|
| 0 | 통계 | 20.0 | 통계학과는... |
| 1 | 수학 | 30.0 | 수학과는... |
| 2 | 과학 | 25.0 | 과학학과는... |
| 3 | 신설학과 | NaN | 이 학과는 내년에 신설될 예정이고... |
# 경우4: 두 학과 모두 살림
pd.merge(df1,df2)
pd.merge(df1,df2,how='outer')| dept | count | desc | |
|---|---|---|---|
| 0 | 통계 | 20.0 | 통계학과는... |
| 1 | 수학 | 30.0 | 수학과는... |
| 2 | 과학 | 25.0 | 과학학과는... |
| 3 | IAB | 50.0 | NaN |
| 4 | 신설학과 | NaN | 이 학과는 내년에 신설될 예정이고... |
6. concat, merge 를 이용한 데이터 합치기
# 예제 – 전북대학교 통계학과 교과목
주어진 자료가 아래와 같다.
df_course2023 = pd.DataFrame({
'name':['최규빈']*3+['최혜미']*2+['이영미']+['양성준'],
'year':[2023]*7,
'course':['파이썬프로그래밍', '데이터시각화', '기계학습활용','수리통계1', '수리통계2','회귀분석1','통계수학']})
df_course2023| name | year | course | |
|---|---|---|---|
| 0 | 최규빈 | 2023 | 파이썬프로그래밍 |
| 1 | 최규빈 | 2023 | 데이터시각화 |
| 2 | 최규빈 | 2023 | 기계학습활용 |
| 3 | 최혜미 | 2023 | 수리통계1 |
| 4 | 최혜미 | 2023 | 수리통계2 |
| 5 | 이영미 | 2023 | 회귀분석1 |
| 6 | 양성준 | 2023 | 통계수학 |
df_course2024 = pd.DataFrame({
'name':['최규빈','이영미','이영미','양성준','최혜미'],
'year':[2024]*5,
'course':['기계학습활용','수리통계1', '수리통계2','회귀분석1','통계수학']})
df_course2024| name | year | course | |
|---|---|---|---|
| 0 | 최규빈 | 2024 | 기계학습활용 |
| 1 | 이영미 | 2024 | 수리통계1 |
| 2 | 이영미 | 2024 | 수리통계2 |
| 3 | 양성준 | 2024 | 회귀분석1 |
| 4 | 최혜미 | 2024 | 통계수학 |
df_score = pd.DataFrame({
'name':['최규빈','최규빈','이영미','이영미','양성준','양성준','최혜미','최혜미'],
'year':[2023,2024]*4,
'score':[1, 1.2, 5,5,5,5,5,5]})
df_score| name | year | score | |
|---|---|---|---|
| 0 | 최규빈 | 2023 | 1.0 |
| 1 | 최규빈 | 2024 | 1.2 |
| 2 | 이영미 | 2023 | 5.0 |
| 3 | 이영미 | 2024 | 5.0 |
| 4 | 양성준 | 2023 | 5.0 |
| 5 | 양성준 | 2024 | 5.0 |
| 6 | 최혜미 | 2023 | 5.0 |
| 7 | 최혜미 | 2024 | 5.0 |
df_sex = pd.DataFrame({'name':['최규빈','이영미','양성준','최혜미'],
'sex':['male','female','male','female']})
df_sex| name | sex | |
|---|---|---|
| 0 | 최규빈 | male |
| 1 | 이영미 | female |
| 2 | 양성준 | male |
| 3 | 최혜미 | female |
주어진 정보를 바탕으로, 4개의 데이터 프레임을 결합하라.
(풀이)
pd.concat([df_course2023,df_course2024])\
.merge(df_score, on=['name','year'])\
.merge(df_sex, on='name')| name | year | course | score | sex | |
|---|---|---|---|---|---|
| 0 | 최규빈 | 2023 | 파이썬프로그래밍 | 1.0 | male |
| 1 | 최규빈 | 2023 | 데이터시각화 | 1.0 | male |
| 2 | 최규빈 | 2023 | 기계학습활용 | 1.0 | male |
| 3 | 최규빈 | 2024 | 기계학습활용 | 1.2 | male |
| 4 | 최혜미 | 2023 | 수리통계1 | 5.0 | female |
| 5 | 최혜미 | 2023 | 수리통계2 | 5.0 | female |
| 6 | 최혜미 | 2024 | 통계수학 | 5.0 | female |
| 7 | 이영미 | 2023 | 회귀분석1 | 5.0 | female |
| 8 | 이영미 | 2024 | 수리통계1 | 5.0 | female |
| 9 | 이영미 | 2024 | 수리통계2 | 5.0 | female |
| 10 | 양성준 | 2023 | 통계수학 | 5.0 | male |
| 11 | 양성준 | 2024 | 회귀분석1 | 5.0 | male |
#
7. HW
없음