08wk-2: Pandas – groupby, 데이터프레임의 결합

pandas
Author

최규빈

Published

October 25, 2023

1. 강의영상

2. Imports

import pandas as pd 
import numpy as np

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

  1. sub-dataframe 이 모여있는 묶음체이다.
  2. 반복문을 돌리기에 용이하도록 고안되어있다. (이때 각 반복인자는 (묵음기준,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. 가장 빈번하게 사용하는 상황

# 예시1big 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에 대한 gendercount를 정리하고 있음. 그리고 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

없음