본문 바로가기
Python/Pandas

[Pandas] 판다스 데이터프레임 합치기 (merge, concatenate)

by 인사이티드 2023. 2. 7.

판다스에서는 시리즈나 데이터프레임을 다루기 편하게 하기 위해 여러 함수들을 제공하고 있다.
그 중, 여러 개의 데이터프레임이나 시리즈를 합치는 기능은 빈번히 사용되는 기능들 중 하나이다.


1. concat()

첫 번째는 concat() 메서드이다. concat() 메서드는 이름 그대로 데이터프레임 또는 시리즈를 연결하는 기능이다. 아래 예시처럼 서로 다른 두 데이터프레임을 합칠 수 있다.

df1 = pd.DataFrame(
    {
        "A": ["A0", "A1", "A2", "A3"],
        "B": ["B0", "B1", "B2", "B3"],
        "C": ["C0", "C1", "C2", "C3"],
        "D": ["D0", "D1", "D2", "D3"],
    },
    index=[0,1,2,3]
}

df2 = pd.DataFrame(
    {
        "A": ["A4", "A5", "A6", "A7"],
        "B": ["B4", "B5", "B6", "B7"],
        "C": ["C4", "C5", "C6", "C7"],
        "D": ["D4", "D5", "D6", "D7"],
    },
    index=[4,5,6,7]
)

frames = pd.concat([df1, df2])
frames

=>

	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


위의 경우처럼 인덱스를 설정해준 경우, 데이터프레임의 shape이 인덱스에 맞지 않는다면(위의 경우에서는 row 4개), concat() 호출 시 오류가 난다. 그러나 설정해주지 않는다면 오류가 나지 않고 연결된다. ignore_index = True로 설정해서 기존 인덱스를 무시하고 연결해줄 수 있다.

# 인덱스를 설정한 경우
df1 = pd.DataFrame(
    {
        "A": ["A0", "A1", "A2", "A3"],
        "B": ["B0", "B1", "B2", "B3"],
        "C": ["C0", "C1", "C2", "C3"],
        "D": ["D0", "D1", "D2", "D3"],
    },
    index=[0,1,2,3]
)

df2 = pd.DataFrame(
    {
        "A": ["A4", "A5", "A6", "A7","A8"],
        "B": ["B4", "B5", "B6", "B7","B8"],
        "C": ["C4", "C5", "C6", "C7","C8"],
        "D": ["D4", "D5", "D6", "D7","D8"],
    },
    index=[4,5,6,7]
)

frames = pd.concat([df1, df2])
frames

=>
...
ValueError: Shape of passed values is (5, 4), indices imply (4, 4)


# 인덱스를 설정하지 않은 경우
df1 = pd.DataFrame(
    {
        "A": ["A0", "A1", "A2", "A3"],
        "B": ["B0", "B1", "B2", "B3"],
        "C": ["C0", "C1", "C2", "C3"],
        "D": ["D0", "D1", "D2", "D3"],
    }
)

df2 = pd.DataFrame(
    {
        "A": ["A4", "A5", "A6", "A7","A8"],
        "B": ["B4", "B5", "B6", "B7","B8"],
        "C": ["C4", "C5", "C6", "C7","C8"],
        "D": ["D4", "D5", "D6", "D7","D8"],
    }
)

frames = pd.concat([df1, df2], ignore_index=True)
frames
=>
	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

# df2의 기존 인덱스인 0,1,2,3,4 대신 4,5,6,7,8이 인덱스로 설정되었다.

 

concat() 메서드는 데이터프레임 뿐만 아니라 시리즈도 연결할 수 있다. 그 대신 시리즈 객체를 데이터프레임으로 변경하고, 전치시켜주는 과정을 거쳐야한다.

s1 = pd.Series(["A9","B9","C9","D9"], index=['A','B','C','D'])
frames = pd.concat([frames, s1.to_frame().T], ignore_index=True)
frames
=>
	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


concat() 메서드는 파라미터 axis를 설정하여 행 방향으로 또는 열 방향으로 합칠 수 있다. axis의 기본값은 0으로, 기본적으로는 행 방향으로 합친다. 그러나 axis=1로 설정하여 열 방향으로 합치는 경우도 가능하다.

df1 = pd.DataFrame(
    {
        "A": ["A0", "A1", "A2", "A3"],
        "B": ["B0", "B1", "B2", "B3"],
        "C": ["C0", "C1", "C2", "C3"],
        "D": ["D0", "D1", "D2", "D3"],
    }
)

df2 = pd.DataFrame(
    {
        "E": ["E0","E1","E2","E3"],
        "F": ["F0","F1","F2","F3"],
    }
)

frames = pd.concat([df1, df2], axis=1)
frames
=>
	A	B	C	D	E	F
0	A0	B0	C0	D0	E0	F0
1	A1	B1	C1	D1	E1	F1
2	A2	B2	C2	D2	E2	F2
3	A3	B3	C3	D3	E3	F3


열 방향으로 합칠 때에는 시리즈 객체를 바로 합쳐줄 수 있다.

s1 = pd.Series(['G0','G1','G2','G3'])
frames = pd.concat([frames, s1], axis=1)
frames
=>
	A	B	C	D	E	F	0
0	A0	B0	C0	D0	E0	F0	G0
1	A1	B1	C1	D1	E1	F1	G1
2	A2	B2	C2	D2	E2	F2	G2
3	A3	B3	C3	D3	E3	F3	G3


이 외에도 concat() 메서드는 여러가지 파라미터를 가지고 있다.

pd.concat(
    objs,
    axis=0,
    join="outer",
    ignore_index=False,
    keys=None,
    levels=None,
    names=None,
    verify_integrity=False,
    copy=True,
)
# objs: 데이터프레임 또는 시리즈의 시퀀스
# axis: 합칠 축의 방향
# join: {'inner','outer'}. 기본값은 'outer'이고, 합집합으로 합침. 'inner'는 교집합으로 합침
# ignore_index: True로 설정할 시, 기존 객체의 인덱스 무시
# keys: 시퀀스를 받고 계층을 가진 멀티 인덱스를 생성한다.
# levels: 시퀀스를 받고 멀티 인덱스를 생성한다.



2. merge()

두 번째는 merge() 메서드이다. 판다스의 merge() 메서드 또한 concat()과 마찬가지로 데이터프레임 또는 시리즈를 병합할 수 있는 기능이다. concat()과의 차이점이라면, merge()는 시리즈 또는 데이터프레임 객체를 대상으로 join을 실행한다. SQL의 개념과 유사하다.

아래는 시리즈를 key로 merge()를 수행한 결과이다. 파라미터 on = 'key'로 설정한 결과이다.

left = pd.DataFrame(
    {
        "key": ["K0", "K1", "K2", "K3"],
        "A": ["A0", "A1", "A2", "A3"],
        "B": ["B0", "B1", "B2", "B3"],
    }
)

right = pd.DataFrame(
    {
        "key": ["K0", "K1", "K2", "K3"],
        "C": ["C0", "C1", "C2", "C3"],
        "D": ["D0", "D1", "D2", "D3"],
    }
)

result = pd.merge(left, right, on="key")
result
=>
	key	A	B	C	D
0	K0	A0	B0	C0	D0
1	K1	A1	B1	C1	D1
2	K2	A2	B2	C2	D2
3	K3	A3	B3	C3	D3
# 'key' 컬럼을 중심으로 데이터프레임이 합쳐졌다.


시리즈 대신 데이터프레임을 key로 사용할 수도 있다. 파라미터 on = ['key1', 'key2']로 설정하였다.

left = pd.DataFrame(
    {
        "key1": ["K0", "K0", "K1", "K2"],
        "key2": ["K0", "K1", "K0", "K1"],
        "A": ["A0", "A1", "A2", "A3"],
        "B": ["B0", "B1", "B2", "B3"],
    }
)

right = pd.DataFrame(
    {
        "key1": ["K0", "K1", "K1", "K2"],
        "key2": ["K0", "K0", "K0", "K0"],
        "C": ["C0", "C1", "C2", "C3"],
        "D": ["D0", "D1", "D2", "D3"],
    }
)

result = pd.merge(left, right, on=["key1", "key2"])
result
=>
	key1	key2	A	B	C	D
0	K0	K0	A0	B0	C0	D0
1	K1	K0	A2	B2	C1	D1
2	K1	K0	A2	B2	C2	D2
# 'key1'과 'key2' 컬럼을 중심으로 합쳐졌다.

 

merge() 메서드에는 다양한 파라미터가 존재한다.
left, right는 각각 merge()의 대상이 되는 데이터프레임이다.

pd.merge(
    left,
    right,
    how="inner",
    on=None,
    left_on=None,
    right_on=None,
    left_index=False,
    right_index=False,
    sort=True,
    suffixes=("_x", "_y"),
    copy=True,
    indicator=False,
    validate=None,
)
# how: join 방식을 말한다. {'left','right','outer','inner','cross'}가 있다.
# on: join의 기준이 되는 column 또는 index이다.
# sort: key를 기준으로 데이터프레임을 사전순으로 정렬한다.
# validate: string 값을 전달하면 merge()가 특정 타입인지 체크한다.
			"one-to-one" or "1:1" / "one-to-many" or "1:m" / "many-to-one" or "m:1" / "many-to-many" or "m:m"

참고자료

[1] "Merge, join, concatenate and compare", Pandas, https://pandas.pydata.org/docs/user_guide/merging.html