pandas 100제: 판다스 연습문제와 풀이 · 7장
051–060 결측치와 중복
isna, any, dropna, subset, fillna, 평균·그룹 평균으로 채우기, ffill, duplicated, drop_duplicates 연습문제
이 장의 목차 13개
빈 값(NaN)과 중복 행을 다루는 전처리 문제입니다. 준비 코드의 표에는 빈 값과 중복 행이 섞여 있습니다.
준비 데이터에는 빈 값(붉은 칸)과 완전히 같은 행(갈색)이 섞여 있습니다. 숫자 열의 빈 값은 NaN, 문자열 열의 빈 값은 pandas 2에서 None, pandas 3에서 NaN으로 보이지만 둘 다 isna()가 결측치로 셉니다. 빈 값을 지울지, 0으로 채울지, 평균으로 채울지는 문법이 아니라 데이터의 의미로 정해야 한다는 점을 기억하세요.
준비 코드와 데이터
노트북 첫 셀에 아래 준비 코드를 붙여 넣어 실행한 뒤 문제를 푸세요.
Pythonimport pandas as pd
import numpy as np
df = pd.DataFrame({
'name': ['김민준', '이서연', '박지호', '최수아', '정민서', '최수아'],
'class': ['A', 'B', 'A', 'C', 'B', 'C'],
'score': [85, np.nan, 58, 77, np.nan, 77],
'memo': ['우수', None, None, '성실', '결석', '성실'],
})
이 장 실습 노트북 내려받기 (.ipynb) — 준비 코드와 문제가 들어 있고 답 칸은 비어 있습니다. 코랩에서는 파일 → 노트 업로드로 엽니다.
준비 코드를 실행하면 df는 다음 표가 됩니다(6행 × 4열, 맨 왼쪽 숫자는 인덱스).
결과 name class score memo
0 김민준 A 85.0 우수
1 이서연 B NaN NaN
2 박지호 A 58.0 NaN
3 최수아 C 77.0 성실
4 정민서 B NaN 결석
5 최수아 C 77.0 성실
장 안의 문제는 번호 순서대로 이어집니다. 앞 문제에서 만든 열이나 변수를 다음 문제가 쓸 수 있으니, 중간부터 풀 때는 준비 코드와 앞의 필요한 문제를 먼저 실행하세요.
051. 열별 결측치 개수
열마다 빈 값이 몇 개인지 구하세요.
힌트 보기
isna()는 칸마다 True/False를 돌려줍니다. 열마다 더하면 결측치 수가 됩니다.
정답 보기
Pythondf.isna().sum()
결과name 0
class 0
score 2
memo 2
dtype: int64
풀이: isna가 만든 불리언 표를 열별로 더해 빠진 값 수를 셉니다. 빈 문자열은 NaN과 다릅니다.
052. 결측치가 있는 행
빈 값이 하나라도 있는 행을 고르세요.
힌트 보기
isna().any(axis=1) — 행마다 하나라도 True인지 봅니다.
정답 보기
Pythondf[df.isna().any(axis=1)]
결과 name class score memo
1 이서연 B NaN NaN
2 박지호 A 58.0 NaN
4 정민서 B NaN 결석
풀이: any(axis=1)는 각 행에서 하나라도 결측치인지 확인합니다.
pandas 2.x에서는 값은 같고 표시만 다음과 같습니다.
결과 name class score memo
1 이서연 B NaN None
2 박지호 A 58.0 None
4 정민서 B NaN 결석053. 결측치 행 지우기
빈 값이 있는 행을 모두 지우세요.
힌트 보기
dropna()를 인자 없이 쓰면 결측치가 하나라도 있는 행을 지웁니다.
정답 보기
Pythondf.dropna()
결과 name class score memo
0 김민준 A 85.0 우수
3 최수아 C 77.0 성실
5 최수아 C 77.0 성실
풀이: dropna 기본 동작은 결측치가 하나라도 있는 행 제거입니다. 남길 관측치가 과도하게 줄지 확인합니다.
054. 특정 열 기준으로 지우기
score가 빈 행만 지우세요.
힌트 보기
dropna(subset=["열"]).
정답 보기
Pythondf.dropna(subset=['score'])
결과 name class score memo
0 김민준 A 85.0 우수
2 박지호 A 58.0 NaN
3 최수아 C 77.0 성실
5 최수아 C 77.0 성실
풀이: subset으로 삭제 판단에 사용할 열을 제한하므로 다른 열의 결측치 때문에 행을 버리지 않습니다.
memo만 빈 행은 남습니다.
pandas 2.x에서는 값은 같고 표시만 다음과 같습니다.
결과 name class score memo
0 김민준 A 85.0 우수
2 박지호 A 58.0 None
3 최수아 C 77.0 성실
5 최수아 C 77.0 성실055. 0으로 채우기
score의 빈 값을 0으로 채운 Series를 구하세요(원본은 그대로 둡니다).
힌트 보기
fillna(0).
정답 보기
Pythondf['score'].fillna(0)
결과0 85.0
1 0.0
2 58.0
3 77.0
4 0.0
5 77.0
Name: score, dtype: float64
풀이: 0을 넣으면 평균 등 후속 계산이 달라집니다. 결측치가 실제 0을 의미하는지 먼저 확인합니다.
056. 평균으로 채우기
score의 빈 값을 평균으로 채운 Series를 구하세요.
힌트 보기
fillna() 괄호 안에 df["score"].mean()을 넣습니다.
정답 보기
Pythondf['score'].fillna(df['score'].mean())
결과0 85.00
1 74.25
2 58.00
3 77.00
4 74.25
5 77.00
Name: score, dtype: float64
풀이: mean은 결측치를 제외한 값으로 계산합니다. 중복 행도 포함되므로 전처리 순서를 확인합니다.
057. 그룹 평균으로 채우기
score의 빈 값을 같은 반의 평균으로 채우세요. 같은 반에 값이 없으면 빈 값으로 남습니다.
힌트 보기
groupby("class")["score"].transform("mean")은 행마다 그 반의 평균을 돌려줍니다. 이것을 fillna에 넣으세요.
정답 보기
Pythondf['score'].fillna(df.groupby('class')['score'].transform('mean'))
결과0 85.0
1 NaN
2 58.0
3 77.0
4 NaN
5 77.0
Name: score, dtype: float64
풀이: transform 결과는 원래 인덱스에 맞춰집니다. 그룹 안 유효 점수가 없으면 평균도 NaN입니다.
transform은 그룹 결과를 원래 행 수에 맞춰 돌려줍니다. B반은 점수가 모두 비어 있어 채워지지 않습니다.
058. 앞의 값으로 채우기
memo의 빈 값을 바로 위 행의 값으로 채우세요.
힌트 보기
바로 위 값으로 채우는 함수는 ffill()입니다.
정답 보기
Pythondf['memo'].ffill()
결과0 우수
1 우수
2 우수
3 성실
4 결석
5 성실
Name: memo, dtype: str
풀이: ffill은 현재 행 순서에 의존합니다. 이 예제에서는 문법을 연습하며 실제 서로 다른 사람의 메모를 임의로 이월하면 안 됩니다.
pandas 2.x에서는 마지막 줄이 dtype: object로 보입니다. 값은 같습니다.
059. 중복 행 찾기
앞에서 이미 나온 행과 완전히 같은 중복 행이 몇 개인지 세고, 그 행을 보이세요.
힌트 보기
duplicated()는 행마다 "앞에 같은 행이 있었나"를 True/False로 돌려줍니다.
정답 보기
Pythonprint(df.duplicated().sum())
df[df.duplicated()]
결과1
name class score memo
5 최수아 C 77.0 성실
풀이: duplicated는 기본적으로 첫 등장은 남기고 뒤의 완전 중복을 표시합니다. 바로 앞 행과 같아야 하는 것은 아닙니다.
060. 기준 열로 중복 지우기
name이 같은 행은 마지막 행만 남기세요.
힌트 보기
drop_duplicates(subset="name", keep="last").
정답 보기
Pythondf.drop_duplicates(subset='name', keep='last')
결과 name class score memo
0 김민준 A 85.0 우수
1 이서연 B NaN NaN
2 박지호 A 58.0 NaN
4 정민서 B NaN 결석
5 최수아 C 77.0 성실
풀이: name만 중복 기준으로 보고 현재 순서의 마지막 행을 남깁니다. 최신 날짜를 의미하려면 먼저 날짜로 정렬해야 합니다.
pandas 2.x에서는 값은 같고 표시만 다음과 같습니다.
결과 name class score memo
0 김민준 A 85.0 우수
1 이서연 B NaN None
2 박지호 A 58.0 None
4 정민서 B NaN 결석
5 최수아 C 77.0 성실이 장 요약
| 문법 | 하는 일 | 문제 |
|---|---|---|
df.isna().sum() | 열별 결측치 수 | 051 |
df[df.isna().any(axis=1)] | 결측치가 있는 행 | 052 |
df.dropna() / dropna(subset=[열]) | 결측 행 지우기(전체 / 특정 열 기준) | 053–054 |
s.fillna(값) | 빈 값 채우기 | 055–056 |
s.fillna(df.groupby(g)[열].transform("mean")) | 그룹 평균으로 채우기 | 057 |
s.ffill() | 위 값으로 채우기 | 058 |
df.duplicated() | 앞에 같은 행이 있었나 | 059 |
df.drop_duplicates(subset=, keep=) | 중복 지우기 | 060 |
이 장의 점검
빈 값을 0으로 바꾸기·평균으로 채우기·행 삭제가 분석에 주는 차이를 설명하세요. 중복과 결측치 처리에는 실제 기록 의미가 필요합니다.
참고: pandas 공식 문서 · 문법이 기억나지 않으면 부록 치트시트를 찾아보세요.