[6주차] 데이터 병합

2024. 1. 15. 16:13Portfolio/BDA 7기

Contents 접기

데이터 병합

데이터 병합은 DE, DA, DS 등 데이터를 다루는 직군이라면 필수적으로 알아야 하는 개념이다.

SQL 쪽에서는 기본적으로 join을 이용하여 테이블 query를 추출하는데,

데이터베이스 시스템에서 내부적으로 최적화되어 많은 데이터를 효율적으로 처리 가능!

 

반면, python은 범용 프로그래밍 언어이기 때문에 데이터 처리에 특화된 최적화가 내장되어 있지 않다. 

이는 대용량 데이터를 다루거나 복잡한 데이터 조작이 필요한 경우 성능 이슈가 발생할 수 있는 것!

 


1. Concat()

이전 포스팅에서 간단히 다룬 concat() 함수는 데이터프레임끼리 합쳐지는 것이다.

그렇기 때문에 따로 어떤 join 조건은 없다.

 

concat 함수의 매개변수에는 axis ignore_index 가 있다.

# axis : 데이터프레임을 이어붙이는 방향을 지정하는 것
✅ axis = 0 : 수직 방향, 위아래로 이어붙임
✅ axis = 1 : 수평 방향, 좌우로 이어붙임

# ignore_index : 병합된 결과에 대한 인덱스 재설정 여부
✅ ignore_index = True : 새로운 연속적인 정수로 인덱스 재설정
✅ ignore_index = False : 각각의 데이터프레임의 인덱스 유지

 

 

코드 예제를 통해 알아보자

import pandas as pd

df1 = pd.DataFrame({'A':[1,2,3], 'B':[4,5,6]})
df2 = pd.DataFrame({'A':[4,5], 'B':[6,7]})
df3 = pd.DataFrame({'A':[7,8,9], 'B':[10,11,12], 'C':[13,14,15]})

display(df1)
display(df2)

df1
df2

 

display(pd.concat([df1,df2], axis=0)) # 0행, 1열 기준
display(pd.concat([df1,df2], axis=1)) # 0행, 1열 기준
display(pd.concat([df2,df1], axis=0, ignore_index=True)) # 인덱스를 새롭게 정렬

가장 먼저 쓴 데이터프레임이 기본 축이 되는 것을 기억하자

 

concat 함수는 시계열 인덱스 날짜 기준으로 데이터를 붙이는 경우나

아예 다른 데이터 (공통 기준이 없는 경우)를 붙여야 하는 경 사용한다.

 

 

 

merge()

merge 함수는 두 개의 데이터프레임을 특정 열 또는 인덱스를 기준으로 합치는 데 사용된다.

이때 join 매개변수는 두 데이터프레임에서 어떤 열을 기준으로 합칠지를 지정한다.

이 기준 열을 Primary Key(주 키)라고 부르며, 각 데이터프레임에서 해당 열의 값이 일치하는 행들을 찾아 합친다.

 

# merge 함수의 파라미터
1. left & right : 합치려는 두 데이터프레임을 지정 ex) pd.merge(left, right, ...)
2. on : 합치는 기준이 되는 열의 이름을 지정
3. how : 합치는 방법 지정 (inner, outer, left, right 등)
4. left_on & right_on : 합치는 두 데이터프레임에서 join 키로 사용할 컬럼 목록 지정
5. left_index & right_index : 합치는 두 데이터프레임에서 join 기준 인덱스 사용할지 여부

 

코드 예제로 쉽게 이해해보자

df1 = pd.DataFrame({'이름': {'홍길동','박길동','김길동','이길동'], '반':['파문응','파문기','데분기','데분중']})
df2 = pd.dataFrame({'이름':['홍길동','박길동','오길동','이길동'], '점수':[100,50,80,90]})

display(df1)
display(df2)

df1
df2

 

join을 하는 경우는 대부분 하나의 테이블, 데이터프레임에서 얻을 수 없는 결과들을

한 번에 테이블로 만들어서 다양한 데이터를 분석하기 위함이다.

예를 들어, 임의로 만든 데이터에서 반과 점수를 같이 합쳐서 길동이들의  반별 점수를 알 수 있다.

pd.merge(df1, df2, on='이름')

inner join의 디폴트는 공통의 교집합만 출력

 

 

join 키가 두 개 이상인 경우는 어떻게 될까?

df1 = pd.DataFrame({'이름':['홍길동','박길동','김길동','이길동'], '반':['파문응','파문기','데분기','데분중'],'학번':[20,21,22,23]})
df2 = pd.DataFrame({'이름':['홍길동','박길동','오길동','이길동'], '점수':[100,50,80,90],'학번':[20,19,22,23]})

display(df1)
display(df2)

    df1                                                                                                                    df2

 

# 2개 이상을 join key로 사용
pd.merge(df1, df2, on=['이름', '학번'])

이름과 학번의 공통 교집합을 기준으로 병합된다

 

 

left_on, right_on

left_on & right_on 파라미터는 합치는 두 데이터프레임에서 join 키로 사용할 컬럼 목록 지정한다.

따라서 컬럼명은 다르지만 값이 같다면 그 내용을 지정해서 join 하게 된다.

df1 = pd.DataFrame({'이름':['홍길동','박길동','김길동','이길동'], '반':['파문응','파문기','데분기','데분중'],'번호':[20,21,22,23]})
df2 = pd.DataFrame({'이름':['홍길동','박길동','오길동','이길동'], '점수':[100,50,80,90],'학번':[20,19,22,23]})
# 중복이 나오는 경우
pd.merge(df1, df2, left_on='번호', right_on='학번')

# 중복이 나오지 않는 경우
pd.merge(df1, df2, left_on='이름', right_on='이름')

                중복이 나오는 경우                                                                                     중복이 나오지 않는 경우

 

left_on, right_on을 각각 '번호'와 '학번'으로 설정한 경우

join key로 잡은 것 외에 두 개의 컬럼 이름_x, 이름_y의 중복이 발생했다.

 

 

index

'index' 파라미터는 두 개의 데이터프레임을 병합할 때,

어떤 열을 기준으로 데이터를 병합할 것인지 설정하는 파라미터이다.

left_index : 왼쪽 데이터프레임의 인덱스를 사용할지 여부 결정, 기본값은 False
right_index : 오른쪽 데이터프레임의 인덱스를 사용할지 여부를 결정

 

인덱스는 기본 0,1,2,3, ... 순서로 되어 있는데

만약 이름을 인덱스로 지정하면

df_sp = df1.set_index('이름')
print(df_sp)

인덱스가 '이름'으로 설정됨

 

pd.merge(df_sp, df2, left_index = True, right_on='이름')

df_sp 데이터프레임 인덱스를 사용하고, df2 데이터프레임에서 병합의 기준이 되는 열을 '이름'으로 설정하여

공통의 컬럼을 기준으로 데이터를 병합하였다.

 

이때 주의해야 할 점은 left가 있으면

pd.merge(df_sp, df2, left_index = True)

 

right도 지정해야 한다는 것을 잊지 말자!

 

 

how

how 파라미터는 join 방법을 다양하게 설정할 수 있다.

inner : 공통의 교집합 컬럼을 가지고 교집합된 내용들만 병합하는 것
left : 왼쪽 데이터프레임의 join 키를 기준으로 병합
right : 오른쪽 데이터프레임의 join 키를 기준으로 병합
outer : 왼쪽과 오른쪽의 데이터프레임의 join 키에 대한 합집합을 기준으로 병합 

 

코드 예제를 보자

# inner
pd.merge(df1, df2, on='이름', how='inner')

# left
pd.merge(df1, df2, on='이름', how='left')

# right
pd.merge(df1, df2, on='이름'. how='right')

inner, left, right 순

 

inner join을 하면 공통의 교집합 컬럼 중 교집합된 내용들만 병합한다.

left join을 하는 경우 df1의 모든 값은 고정으로 생성되고, 그 옆에 df2의 데이터 중 on 컬럼과 같은 교집합만 붙는다.

따라서 na값이 발생할 수 있음에 주의하자. (right join도 마찬가지 겠지?)

 

# outer
pd.merge(df1, df2, on='이름', how='outer')

 

outer join은 양쪽에 모두 있는 데이터와 한쪽에만 있는 데이터 모두를 포함하는 병합 방식이다.

left join과 right join 결과가 합쳐짐

 

 

샘플 데이터 실습

위의 개념들을 이용해서 샘플 데이터로 데이터를 병합해보자

site = pd.read_csv('survey_site.csv')
survey = pd.read_csv('survey_survey.csv')
vit = pd.read_csv('survey_visited.csv')

display(site)
display(vit)

 

데이터를 합병하기 전 항상 해당 데이터의 로직과 비지니스 도메인 등 데이터베이스의 설계 개념을 이해해야 한다.

그 다음으로는 어떤 컬럼을 기준(left, right, inner)으로 합병할 지 생각해야 한다.

 

                                         site 데이터프레임                                                                                              vit 데이터프레임

 

위의 데이터는 3개의 데이터를 한 번에 join하는 상황이 아닌,

하나하나씩 세 개를 하나의 테이블로 만들어야 한다.

 

3개의 데이터 중 vit 데이터는 메타데이터로, 다른 데이터를 설명하는 정보를 나타낸다.

이러한 데이터와 같이 메타스키마의 개념(DB 등에서 사용되는 데이터 스키마에 대한 메타데이터를 기술하는 구조)에서는

전체를 관리하는 테이블이 항상 존재한다.

 

이제 각각의 데이터를 join 해보자

# site, vit 데이터를 name과 site 기준으로 먼저 병합
mg1 = pd.merge(site, vit, left_on=['name'], right_on=['site'])

# 병합한 데이터를 survey 데이터와 적절한 join key로 병합
pd.merge(mg1, survey, left_on=['ident'], right_on=['taken'])

 

오늘 수업은 너무 어려워서 앞으로 계속 공부가 필요할 것 같다..