05-2
데이터 연결 기초¶
import pandas as pd
df1 = pd.read_csv('doit_pandas_data/data/concat_1.csv')
df2 = pd.read_csv('doit_pandas_data/data/concat_2.csv')
df3 = pd.read_csv('doit_pandas_data/data/concat_3.csv')
- concat 메서드에 연결하려는 데이터프레임을 리스트에 담아 전달하면 연결한 데이터프레임을 반환한다. concat 메서드는 데이터프레임을 연결할 때 위에서 아래 방향으로 연결한다. 그리고 df1, 2, 3은 열의 이름이 모두 A, B, C, D로 같다. 그래서 데이터프레임을 연결한 다음에도 열이 그대로 유지된다.
row_concat = pd.concat([df1, df2, df3])
print(row_concat)
A B C D 0 a0 b0 c0 d0 1 a1 b1 c1 d1 2 a2 b2 c2 d2 3 a3 b3 c3 d3 0 a4 b4 c4 d4 1 a5 b5 c5 d5 2 a6 b6 c6 d6 3 a7 b7 c7 d7 0 a8 b8 c8 d8 1 a9 b9 c9 d9 2 a10 b10 c10 d10 3 a11 b11 c11 d11
- 연결한 데이터프레임에서 행 데이터를 추출해보자. concat 메서드는 전달받은 리스트의 요소 순서대로 데이터를 연결한다. 그래서 기존 데이터프레임에 있던 인덱스도 그대로 유지된다. 다음은 데이터프레임에서 네 번째 행을 추출한 것이다.
print(row_concat.iloc[3,])
A a3 B b3 C c3 D d3 Name: 3, dtype: object
- 데이터프레임에 시리즈 연결하기 이번에는 데이터프레임에 시리즈를 추가해 보겠다. 먼저 리스트를 시리즈로 변환한다.
new_row_series = pd.Series(['n1', 'n2', 'n3', 'n4'])
- concat 메서드로 데이터프레임과 시리즈를 연결해보자. 시리즈가 새로운 행으로 추가될 것 같지만, 행이 아니라 새로운 열로 추가된다. 그래서 NaN이라는 값도 많이 생겼다. 앞으로 NaN을 누락값이라고 부르겠다.
print(pd.concat([df1, new_row_series]))
A B C D 0 0 a0 b0 c0 d0 NaN 1 a1 b1 c1 d1 NaN 2 a2 b2 c2 d2 NaN 3 a3 b3 c3 d3 NaN 0 NaN NaN NaN NaN n1 1 NaN NaN NaN NaN n2 2 NaN NaN NaN NaN n3 3 NaN NaN NaN NaN n4
행이 1개라도 반드시 데이터프레임에 담아 연결해야 한다
시리즈를 데이터프레임의 새로운 행으로 연결하려고 하면 제대로 되지 않는다. 왜 그럴까? 시리즈에는 열 이름이 없기 때문이다. 그래서 시리즈를 새로운 열로 간주하여 0이라는 이름의 열로 추가한 것이다.
행 1개로 구성된 데이터프레임 생성하여 연결하기¶
- 시리즈는 행이 1개인 데이터프레임이라고 생각해도 된다. 다음은 1개의 행을 가지는 데이터프레임을 생성하여 df1에 연결한 것이다.
new_row_df = pd.DataFrame([['n1', 'n1', 'n1', 'n1']], columns=['A', 'B', 'C', 'D'])
print(new_row_df)
A B C D 0 n1 n1 n1 n1
print(pd.concat([df1, new_row_df]))
A B C D 0 a0 b0 c0 d0 1 a1 b1 c1 d1 2 a2 b2 c2 d2 3 a3 b3 c3 d3 0 n1 n1 n1 n1
- concat 메서드는 한 번에 2개 이상의 데이터프레임을 연결할 수 있는 메서드이다. 만약 연결할 데이터프레임이 1개라면 append 메서드를 사용해도 된다. new_row_df는 행 1개로 구성된 데이터프레임이다.
print(df1.append(new_row_df))
A B C D 0 a0 b0 c0 d0 1 a1 b1 c1 d1 2 a2 b2 c2 d2 3 a3 b3 c3 d3 0 n1 n1 n1 n1
/tmp/ipykernel_1314/3141778766.py:1: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead. print(df1.append(new_row_df))
- append 메서드와 딕셔너리를 사용하면 더욱 간편하게 행을 연결할 수 있다. 이때 ignore_index를 True로 설정하면 데이터를 연결한 다음 데이터프레임의 인덱스를 0부터 다시 지정한다.
data_dict ={'A':'n1', 'B':'n2', 'C':'n3', 'D':'n4'}
print(df1.append(data_dict, ignore_index=True))
A B C D 0 a0 b0 c0 d0 1 a1 b1 c1 d1 2 a2 b2 c2 d2 3 a3 b3 c3 d3 4 n1 n2 n3 n4
/tmp/ipykernel_1314/752441816.py:2: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead. print(df1.append(data_dict, ignore_index=True))
마지막 행 데이터의 인덱스가 0에서 4로 바뀌었다.
다양한 방법으로 데이터 연결하기
판다스는 데이터를 연결하는 방법을 제공한다. 다음 예제를 통해 데이터를 연결하는 다양한 방법에 대해 알아보겠다.
다양한 방법으로 데이터 연결하기¶
- ignore_index 인자 사용하기 바로 앞에서 실습했던 내용이다. ingore_index를 True로 지정하면 데이터를 연결한 다음 데이터프레임의 인덱스를 0부터 다시 지정한다.
row_concat_i = pd.concat([df1, df2, df3], ignore_index=True)
print(row_concat_i)
A B C D 0 a0 b0 c0 d0 1 a1 b1 c1 d1 2 a2 b2 c2 d2 3 a3 b3 c3 d3 4 a4 b4 c4 d4 5 a5 b5 c5 d5 6 a6 b6 c6 d6 7 a7 b7 c7 d7 8 a8 b8 c8 d8 9 a9 b9 c9 d9 10 a10 b10 c10 d10 11 a11 b11 c11 d11
- 열 방향으로 데이터 연결하기
만약 행 방향이 아니라 열 방향으로 데이터를 연결하려면 어떻게 해야 할까? concat 메서드의 axis 인자를 1로 지정하면 된다. 다음은 df1, df2, df3을 열 방향으로 연기한 것이다. axis의 기본값은 0이다.
col_concat = pd.concat([df1, df2, df3], axis=1)
print(col_concat)
A B C D A B C D A B C D 0 a0 b0 c0 d0 a4 b4 c4 d4 a8 b8 c8 d8 1 a1 b1 c1 d1 a5 b5 c5 d5 a9 b9 c9 d9 2 a2 b2 c2 d2 a6 b6 c6 d6 a10 b10 c10 d10 3 a3 b3 c3 d3 a7 b7 c7 d7 a11 b11 c11 d11
- 만약 같은 열 이름이 있는 데이터프레임에서 열 이름으로 데이터를 추출하면 해당 열 이름의 데이터를 모두 추출한다.
print(col_concat['A'])
A A A 0 a0 a4 a8 1 a1 a5 a9 2 a2 a6 a10 3 a3 a7 a11
- 다음과 같이 입력하면 간편하게 새로운 열을 추가할 수도 있다.
col_concat['new_col_list'] = ['n1', 'n2', 'n3', 'n4']
print(col_concat)
A B C D A B C D A B C D new_col_list 0 a0 b0 c0 d0 a4 b4 c4 d4 a8 b8 c8 d8 n1 1 a1 b1 c1 d1 a5 b5 c5 d5 a9 b9 c9 d9 n2 2 a2 b2 c2 d2 a6 b6 c6 d6 a10 b10 c10 d10 n3 3 a3 b3 c3 d3 a7 b7 c7 d7 a11 b11 c11 d11 n4
- 과정 2에서는 데이터프레임의 열 이름을 유지한 채 연결했기 때문에 열 이름이 중복되었다. 다음은 ignore_index를 True로 지정하여 열 이름을 다시 지정한 것이다.
print(pd.concat([df1, df2, df3], axis=1, ignore_index=True))
0 1 2 3 4 5 6 7 8 9 10 11 0 a0 b0 c0 d0 a4 b4 c4 d4 a8 b8 c8 d8 1 a1 b1 c1 d1 a5 b5 c5 d5 a9 b9 c9 d9 2 a2 b2 c2 d2 a6 b6 c6 d6 a10 b10 c10 d10 3 a3 b3 c3 d3 a7 b7 c7 d7 a11 b11 c11 d11
6. 공통 열과 공통 인덱스만 연결하기¶
만약 열 이름의 일부가 서로 다른 데이터프레임을 연결하면 어떻게 될까? 앞에서 사용한 df1, df2, df3의 열 이름을 다시 지정하겠다.
df1.columns = ['A', 'B', 'C', 'D']
df2.columns = ['E', 'F', 'G', 'H']
df3.columns = ['A', 'C', 'F', 'H']
print(df1)
print(type(df1))
A B C D 0 a0 b0 c0 d0 1 a1 b1 c1 d1 2 a2 b2 c2 d2 3 a3 b3 c3 d3 <class 'pandas.core.frame.DataFrame'>
print(df2)
print(type(df2))
E F G H 0 a4 b4 c4 d4 1 a5 b5 c5 d5 2 a6 b6 c6 d6 3 a7 b7 c7 d7 <class 'pandas.core.frame.DataFrame'>
print(df3)
print(type(df3))
A C F H 0 a8 b8 c8 d8 1 a9 b9 c9 d9 2 a10 b10 c10 d10 3 a11 b11 c11 d11 <class 'pandas.core.frame.DataFrame'>
- 새롭게 열 이름을 부여한 데이터프레임 3개를 concat 메서드로 연결해 보겠다. 열 이름이 정렬되며 연골되었다. 그리고 데이터프레임에 없는 열 이름의 데이터는 누락값으로 처리되었다. 누락값 없이 데이터를 연결하는 방법은 없을까?
row_concat = pd.concat([df1, df2, df3])
print(row_concat)
A B C D E F G H 0 a0 b0 c0 d0 NaN NaN NaN NaN 1 a1 b1 c1 d1 NaN NaN NaN NaN 2 a2 b2 c2 d2 NaN NaN NaN NaN 3 a3 b3 c3 d3 NaN NaN NaN NaN 0 NaN NaN NaN NaN a4 b4 c4 d4 1 NaN NaN NaN NaN a5 b5 c5 d5 2 NaN NaN NaN NaN a6 b6 c6 d6 3 NaN NaN NaN NaN a7 b7 c7 d7 0 a8 NaN b8 NaN NaN c8 NaN d8 1 a9 NaN b9 NaN NaN c9 NaN d9 2 a10 NaN b10 NaN NaN c10 NaN d10 3 a11 NaN b11 NaN NaN c11 NaN d11
- 데아터프레임의 공통 열만 골라 연결하면 누락값이 생기지 않을 것이다. 공통 열만 골라서 연결하려면 join 인자를 inner로 지정해야 한다. 아쉽게도 df1, df2, df3은 공통 열이 없다. 따라서 새 데이터프레임의 공통 열을 연결한 결괏값으로 Empty DataFrame이 출력된다.
print(pd.concat([df1, df2, df3], join='inner'))
A C 0 a0 c0 1 a1 c1 2 a2 c2 3 a3 c3 0 a8 b8 1 a9 b9 2 a10 b10 3 a11 b11
- df1, df3의 공통 열만 골라 연결해보자. 그러면 공통열인 A와 C만 연결된다.
print(pd.concat([df1, df3], ignore_index=False, join='inner'))
A C 0 a0 c0 1 a1 c1 2 a2 c2 3 a3 c3 0 a8 b8 1 a9 b9 2 a10 b10 3 a11 b11
- 이번에는 데이터프레임을 행 방향으로 연결해보자. df1, df2, df3의 인덱스를 다시 지정해보자.
df1.index = [0, 1, 2, 3]
df2.index = [4, 5, 6, 7]
df3.index = [0, 2, 5, 7]
print(df1)
A B C D 0 a0 b0 c0 d0 1 a1 b1 c1 d1 2 a2 b2 c2 d2 3 a3 b3 c3 d3
print(df2)
E F G H 4 a4 b4 c4 d4 5 a5 b5 c5 d5 6 a6 b6 c6 d6 7 a7 b7 c7 d7
print(df3)
A C F H 0 a8 b8 c8 d8 2 a9 b9 c9 d9 5 a10 b10 c10 d10 7 a11 b11 c11 d11
- concat 메서드로 df1, df2, df3을 행 방향으로 연결하면 과정 2와 비슷한 결과가 출력된다.
col_concat = pd.concat([df1, df2, df3], axis = 1)
print(col_concat)
A B C D E F G H A C F H 0 a0 b0 c0 d0 NaN NaN NaN NaN a8 b8 c8 d8 1 a1 b1 c1 d1 NaN NaN NaN NaN NaN NaN NaN NaN 2 a2 b2 c2 d2 NaN NaN NaN NaN a9 b9 c9 d9 3 a3 b3 c3 d3 NaN NaN NaN NaN NaN NaN NaN NaN 4 NaN NaN NaN NaN a4 b4 c4 d4 NaN NaN NaN NaN 5 NaN NaN NaN NaN a5 b5 c5 d5 a10 b10 c10 d10 6 NaN NaN NaN NaN a6 b6 c6 d6 NaN NaN NaN NaN 7 NaN NaN NaN NaN a7 b7 c7 d7 a11 b11 c11 d11
- 과정 9와 비슷한 방법으로 df1, df3의 공통 행만 골라 연결해보자. 그러면 공통 행인 0과 2만 출력된다.
print(pd.concat([df1, df3], axis = 1, join='inner'))
A B C D A C F H 0 a0 b0 c0 d0 a8 b8 c8 d8 2 a2 b2 c2 d2 a9 b9 c9 d9
외부 조인과 내부 조인¶
앞의 실습 예제는 데이터베이스의 주요 개념 중 하나인 내부 조인(Inner Join)과 외부 조인(Outer Join)을 실습한 것이다. 만약 두 개념이 잘 이해되지 않는다면 아래에 정리한 내용을 읽어보자.
내부 조인¶
둘 이상의 데이터프레임에서 조건에 맞는 행을 연결하는 것이다.
외부 조인¶
외부 조인은 두 데이터프레임 중 어떤 데이터프레임을 기준으로 할 것인지에 따라 왼쪽 외부 조인(Left Outer Join)과 오른쪽 외부 조인(Right Outer Join), 완전 외부 조인(Full Outer Join)으로 나눌 수 있다. 왼쪽 외부 조인은 데이터프레임을 연결할 때 왼쪽 데이터프레임을 모두 포함하여 연결하는 것이고 오른쪽 외부 조인은 데이터프레임을 연결할 때 오른쪽 데이터 프레임을 모두 포함하여 연결하는 것이다.
출처 : Do it! 데이터 분석을 위한 판다스
'Python > Pandas' 카테고리의 다른 글
<파이썬 판다스> Chapter 06-1 누락값 처리하기 (0) | 2023.05.04 |
---|---|
<파이썬 판다스> Chapter 05-3 데이터 연결 마무리 (0) | 2023.05.02 |
<파이썬 판다스> Chapter 05-1 분석하기 좋은 데이터 (0) | 2023.05.02 |
<파이썬 판다스> Chapter 04-5 seaborn 라이브러리로 그래프 스타일 설정하기 (0) | 2023.04.30 |
<파이썬 판다스> Chapter 04-4 데이터프레임과 시리즈로 그래프 그리기 (0) | 2023.04.30 |