- titanic 데이터 셋을 활용하여 knn 모델을 구현한다.
- 가장 높은 일반화 성능을 갖는 k의 값은 무엇인지 찾아보자.
필요한 라이브러리를 임포트합니다.
CSV 파일에서 데이터를 불러옵니다.
PassengerId Survived Pclass ... Fare Cabin Embarked 0 1 0 3 ... 7.2500 NaN S 1 2 1 1 ... 71.2833 C85 C 2 3 1 3 ... 7.9250 NaN S 3 4 1 1 ... 53.1000 C123 S 4 5 0 3 ... 8.0500 NaN S ... ... ... ... ... ... ... ... 886 887 0 2 ... 13.0000 NaN S 887 888 1 1 ... 30.0000 B42 S 888 889 0 3 ... 23.4500 NaN S 889 890 1 1 ... 30.0000 C148 C 890 891 0 3 ... 7.7500 NaN Q [891 rows x 12 columns]
컬럼명과 데이터 타입을 확인합니다.
Index(['PassengerId', 'Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp',
'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked'], dtype='object')
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 PassengerId 891 non-null int64
1 Survived 891 non-null int64
2 Pclass 891 non-null int64
3 Name 891 non-null object
4 Sex 891 non-null object
5 Age 714 non-null float64
6 SibSp 891 non-null int64
7 Parch 891 non-null int64
8 Ticket 891 non-null object
9 Fare 891 non-null float64
10 Cabin 204 non-null object
11 Embarked 889 non-null object
dtypes: float64(2), int64(5), object(5)
891개의 샘플, 12개의 컬럼. 타깃 변수는 Survived(생존 여부: 0 또는 1). 결측치는 Age, Cabin, Embarked에 존재합니다.
test_size=0.1 (10% 테스트), random_state=0으로 재현성 확보
((801, 2), (90, 2), (801,), (90,))
0.6 테스트 세트의 정확도 : 0.60
2개의 특성(Pclass, SibSp)만 사용한 기본 모델의 정확도는 60%에 불과합니다. 더 많은 특성과 전처리가 필요합니다.
- 레이블 인코딩 — 범주형 데이터를 숫자로 변환 (male → 1, female → 2)
- 결측치 처리 — Age 컬럼의 결측값을 평균으로 대체
Series.map() — Series를 대상으로 원하는 함수 적용 또는 값을 대체합니다. dict, Series를 인자로 사용합니다.
<class 'pandas.core.frame.DataFrame'> RangeIndex: 891 entries, 0 to 890 Data columns (total 13 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 PassengerId 891 non-null int64 1 Survived 891 non-null int64 2 Pclass 891 non-null int64 3 Name 891 non-null object 4 Sex 891 non-null object 5 Age 891 non-null float64 6 SibSp 891 non-null int64 7 Parch 891 non-null int64 8 Ticket 891 non-null object 9 Fare 891 non-null float64 10 Cabin 204 non-null object 11 Embarked 889 non-null object 12 Sex_num 891 non-null int64 dtypes: float64(2), int64(6), object(5)
Sex_num 컬럼이 추가되었고, Age 결측치가 모두 평균값으로 대체되어 891개 non-null이 되었습니다.
Pclass, SibSp, Sex_num, Age 4개 특성을 사용합니다.
((801, 4), (90, 4), (801,), (90,))
테스트 세트의 정확도 : 0.76
전처리 후 정확도가 60% → 76%로 크게 향상되었습니다. 특성 엔지니어링의 중요성을 확인할 수 있습니다.
k=1부터 21까지 2씩 증가시키며 학습용/테스트용 정확도를 측정합니다.
k : 1 | 학습: 0.885 | 테스트: 0.756 k : 3 | 학습: 0.863 | 테스트: 0.800 k : 5 | 학습: 0.850 | 테스트: 0.800 k : 7 | 학습: 0.839 | 테스트: 0.733 k : 9 | 학습: 0.830 | 테스트: 0.722 k : 11 | 학습: 0.826 | 테스트: 0.744 k : 13 | 학습: 0.824 | 테스트: 0.756 k : 15 | 학습: 0.815 | 테스트: 0.744 k : 17 | 학습: 0.805 | 테스트: 0.756 k : 19 | 학습: 0.792 | 테스트: 0.711 k : 21 | 학습: 0.790 | 테스트: 0.722
- k=3, 5일 때 테스트 정확도 80%로 가장 높음
- k=1은 과대적합(overfitting) — 학습 정확도는 높지만 테스트는 낮음
- k가 커질수록 학습 정확도는 감소 (모델이 단순해짐)
- 최적의 k는 3 또는 5
데이터프레임으로 정리하고 시각화합니다.
tr_acc test_acc 1 0.885144 0.755556 3 0.862672 0.800000 5 0.850187 0.800000 7 0.838951 0.733333 9 0.830212 0.722222 11 0.826467 0.744444 13 0.823970 0.755556 15 0.815231 0.744444 17 0.805243 0.755556 19 0.791511 0.711111 21 0.790262 0.722222
파란색 선(tr_acc)은 k가 증가할수록 하락 (과대적합 해소), 주황색 선(test_acc)은 k=3~5에서 정점을 찍은 후 하락합니다. 즉 k=3 또는 5가 가장 적절한 일반화 성능을 보입니다.
핵심 정리
KNN은 단순하지만 특성 스케일링, 결측치 처리, 하이퍼파라미터 k 튜닝이 중요합니다.
과대적합 vs 과소적합
k가 작으면 과대적합, k가 크면 과소적합. 교차 검증으로 최적 k를 찾는 습관을 기르세요.
EDA 습관화
모델링 전 항상 데이터 분포, 결측치, 이상치를 먼저 탐색하세요.