본문으로 건너뛰기

pandas 100제: 판다스 연습문제와 풀이 · 10장

081–090 합치기와 모양 바꾸기

merge inner·left·outer, left_on·right_on, indicator, concat, melt, pivot, crosstab, explode 연습문제

9분 읽기

이 장의 목차 13개

여러 표를 합치고, 넓은 표와 긴 표를 오가는 문제입니다.

students와 clubs를 inner, left, outer로 합친 결과 비교
students와 clubs를 inner, left, outer로 합친 결과 비교

merge는 키 값이 같은 행끼리 짝을 지어 옆으로 붙입니다. how="inner"는 양쪽에 모두 있는 키만, how="left"는 왼쪽 표의 행을 모두 남기고, how="outer"는 어느 한쪽에라도 있으면 남깁니다. 짝이 없는 칸은 NaN이 됩니다.

과목이 열인 넓은 표와 과목이 값인 긴 표를 melt와 pivot으로 오가는 그림
과목이 열인 넓은 표와 과목이 값인 긴 표를 melt와 pivot으로 오가는 그림

사람이 읽기 좋은 넓은 표(과목마다 열)와, 그래프·집계에 편한 긴 표(과목 이름이 한 열의 값)는 서로 바꿀 수 있습니다. melt는 열 이름을 값으로 내리고, pivot은 값을 다시 열 이름으로 올립니다.

준비 코드와 데이터

노트북 첫 셀에 아래 준비 코드를 붙여 넣어 실행한 뒤 문제를 푸세요.

Pythonimport pandas as pd

students = pd.DataFrame({'name': ['김민준', '이서연', '박지호', '최수아'],
                         'class': ['A', 'B', 'A', 'C']})
clubs = pd.DataFrame({'name': ['김민준', '박지호', '정민서'],
                      'club': ['축구', '밴드', '독서']})
scores = pd.DataFrame({'student': ['김민준', '이서연', '박지호', '최수아'],
                       'kor': [85, 92, 58, 77], 'eng': [78, 88, 64, 95]})

이 장 실습 노트북 내려받기 (.ipynb) — 준비 코드와 문제가 들어 있고 답 칸은 비어 있습니다. 코랩에서는 파일 → 노트 업로드로 엽니다.

준비 코드를 실행하면 students는 다음 표가 됩니다(4행 × 2열, 맨 왼쪽 숫자는 인덱스).

결과     name class
0  김민준     A
1  이서연     B
2  박지호     A
3  최수아     C

준비 코드를 실행하면 clubs는 다음 표가 됩니다(3행 × 2열, 맨 왼쪽 숫자는 인덱스).

결과     name  club
0  김민준  축구
1  박지호  밴드
2  정민서  독서

준비 코드를 실행하면 scores는 다음 표가 됩니다(4행 × 3열, 맨 왼쪽 숫자는 인덱스).

결과  student  kor  eng
0  김민준   85   78
1  이서연   92   88
2  박지호   58   64
3  최수아   77   95

장 안의 문제는 번호 순서대로 이어집니다. 앞 문제에서 만든 열이나 변수를 다음 문제가 쓸 수 있으니, 중간부터 풀 때는 준비 코드와 앞의 필요한 문제를 먼저 실행하세요.

081. 공통 열로 합치기

students와 clubs를 name으로 합치세요(양쪽에 있는 학생만).

힌트 보기

students.merge(clubs, on="name").

정답 보기
Pythonstudents.merge(clubs, on='name')
결과     name class  club
0  김민준     A  축구
1  박지호     A  밴드

풀이: inner 결합이므로 양쪽 표에 공통으로 있는 이름만 남습니다. 이름 중복이 없는 작은 예제입니다.

082. 왼쪽 기준 합치기

모든 학생을 남기고 동아리 정보를 붙이세요.

힌트 보기

merge에 how="left"를 더합니다.

정답 보기
Pythonstudents.merge(clubs, on='name', how='left')
결과     name class  club
0  김민준     A  축구
1  이서연     B   NaN
2  박지호     A  밴드
3  최수아     C   NaN

풀이: left 결합은 왼쪽 학생을 유지합니다. 오른쪽 키가 중복되면 학생 행도 늘 수 있어 키의 유일성을 확인해야 합니다.

짝이 없는 동아리는 NaN이 됩니다.

083. 열 이름이 다를 때

students의 name과 scores의 student를 기준으로 합치세요.

힌트 보기

열 이름이 다르면 left_on="name", right_on="student".

정답 보기
Pythonstudents.merge(scores, left_on='name', right_on='student').drop(columns='student')
결과     name class  kor  eng
0  김민준     A   85   78
1  이서연     B   92   88
2  박지호     A   58   64
3  최수아     C   77   95

풀이: 이름이 다른 연결 열을 각각 지정한 뒤 중복된 이름 정보 열을 제거합니다.

084. 어느 쪽에 있었는지

양쪽 모든 행을 남기고, 행이 어디서 왔는지 표시하세요.

힌트 보기

how="outer"에 indicator=True를 더합니다.

정답 보기
Pythonstudents.merge(clubs, on='name', how='outer', indicator=True)
결과     name class  club      _merge
0  김민준     A  축구        both
1  박지호     A  밴드        both
2  이서연     B   NaN   left_only
3  정민서   NaN  독서  right_only
4  최수아     C   NaN   left_only

풀이: indicator의 both·left_only·right_only를 보면 연결 성공과 한쪽에만 있는 키를 구분할 수 있습니다.

085. 아래로 이어 붙이기

students 아래에 새 학생 한 명(이름 정민서, 반 B)을 붙이고, 인덱스를 0부터 다시 매기세요.

힌트 보기

새 학생을 한 행짜리 DataFrame으로 만든 뒤 pd.concat([students, new], ignore_index=True).

정답 보기
Pythonnew = pd.DataFrame({'name': ['정민서'], 'class': ['B']})
pd.concat([students, new], ignore_index=True)
결과     name class
0  김민준     A
1  이서연     B
2  박지호     A
3  최수아     C
4  정민서     B

풀이: 같은 이름의 열끼리 아래로 붙이고 ignore_index로 행 번호를 새로 만듭니다.

086. 옆으로 이어 붙이기

students와 scores의 kor, eng를 옆으로 붙이세요(행 순서가 같다고 가정).

힌트 보기

pd.concat([...], axis=1)은 옆으로 붙입니다.

정답 보기
Pythonpd.concat([students, scores[['kor', 'eng']]], axis=1)
결과     name class  kor  eng
0  김민준     A   85   78
1  이서연     B   92   88
2  박지호     A   58   64
3  최수아     C   77   95

풀이: axis=1의 concat은 행 라벨을 맞춥니다. 이 예제는 인덱스까지 같으며, 실제 이름 기준 결합은 merge가 적합합니다.

087. 넓은 표를 길게

scores를 student, subject, score 세 열의 긴 표로 바꾸세요.

힌트 보기

melt(id_vars="student", var_name="subject", value_name="score").

정답 보기
Pythonlong = scores.melt(id_vars='student', var_name='subject', value_name='score')
long
결과  student subject  score
0  김민준     kor     85
1  이서연     kor     92
2  박지호     kor     58
3  최수아     kor     77
4  김민준     eng     78
5  이서연     eng     88
6  박지호     eng     64
7  최수아     eng     95

풀이: 학생 이름은 식별자로 두고 과목 열 이름과 점수를 두 열로 내려 긴 형태를 만듭니다.

088. 긴 표를 넓게

87번의 긴 표를 다시 학생별 과목 열로 펼치세요.

힌트 보기

pivot(index="student", columns="subject", values="score").

정답 보기
Pythonlong.pivot(index='student', columns='subject', values='score')
결과subject  eng  kor
student          
김민준    78   85
박지호    64   58
이서연    88   92
최수아    95   77

풀이: pivot은 학생·과목 조합이 유일해야 합니다. 중복이 있으면 집계 방법을 정해 pivot_table을 사용합니다.

089. 교차표

모든 학생에게 동아리 정보를 붙인 뒤(왼쪽 결합), 반(행) × 동아리 가입 여부(열: 가입/미가입)별 학생 수를 교차표로 구하세요.

힌트 보기

왼쪽 결합 뒤 club이 비어 있지 않은지(notna())로 가입 여부를 만들고, pd.crosstab(행, 열)에 넣습니다.

정답 보기
Pythonjoined = students.merge(clubs, on='name', how='left')
pd.crosstab(joined['class'], joined['club'].notna().map({True: '가입', False: '미가입'}))
결과club   가입  미가입
class              
A         2       0
B         0       1
C         0       1

풀이: 결합된 동아리 값이 있는지로 가입 여부를 만들고 반과 교차 집계합니다. 동아리 한 행이 학생 한 명이라는 예제 조건을 확인합니다.

090. 리스트를 행으로 펼치기

다음 표의 tags 열에는 리스트가 들어 있습니다. 태그 하나가 한 행이 되도록 펼치세요.

Pythont = pd.DataFrame({'post': [1, 2], 'tags': [['pandas', 'python'], ['sql']]})
힌트 보기

리스트를 행으로 펼치는 함수는 explode("열")입니다.

정답 보기
Pythont = pd.DataFrame({'post': [1, 2], 'tags': [['pandas', 'python'], ['sql']]})
t.explode('tags')
결과   post    tags
0     1  pandas
0     1  python
1     2     sql

풀이: 리스트의 각 요소가 한 행이 됩니다. 다른 열의 값과 원래 인덱스는 반복됩니다.

이 장 요약

문법하는 일문제
a.merge(b, on="키")공통 키로 합치기(inner)081
merge(..., how="left")왼쪽 행 모두 유지082
merge(left_on=, right_on=)키 열 이름이 다를 때083
merge(how="outer", indicator=True)전부 남기고 출처 표시084
pd.concat([a, b], ignore_index=True)위아래로 붙이기085
pd.concat([a, b], axis=1)옆으로 붙이기(인덱스 기준)086
df.melt(id_vars=, var_name=, value_name=)넓은 표 → 긴 표087
df.pivot(index=, columns=, values=)긴 표 → 넓은 표088
pd.crosstab(행, 열)교차표(빈도)089
df.explode("열")리스트를 행으로 펼치기090

이 장의 점검

merge 전후 행 수를 확인하세요. 연결 키가 오른쪽에서 유일해야 한다면 validate="many_to_one"을 지정해 중복을 오류로 발견할 수 있습니다.

참고: pandas 공식 문서 · 문법이 기억나지 않으면 부록 치트시트를 찾아보세요.

전체 메뉴