결측치 문제는 데이터 분석에서 흔히 마주치는 도전입니다. 이 글에서는 KNN Imputer를 활용하여 결측치를 예측하고 대체하는 방법을 소개합니다. 또한, 결측치 처리 시 주의해야 할 사항들에 대해서도 논의합니다.

주요내용

  • 📊 결측치가 발생한 데이터를 처리하는 다양한 방법 중 KNN Imputer 사용법을 소개합니다.
  • ⚠️ 결측치 예측 모델을 사용할 때의 주의사항과 조건을 설명합니다.
  • 🛠️ sklearn 라이브러리의 KNNImputer 클래스를 활용한 실제 코드 예시를 제공합니다.

결측치 예측 모델


  • 결측이 발생하지 않은 컬럼을 바탕으로 결측치를 예측하는 모델을 학습해서 활용하는 방법

  • 즉, 결측치가 발생한 컬럼을 새로운 label로 보고, 다른 컬럼들을 feature로 봐서 모델을 만들어 예측하여 결측치를 대체하는 방법

image

  • V2와 동시에 결측이 발생한 V3 ~ V5는 제거

  • 살아남은 V1과 V2를 바탕으로 모델 학습 -> 결측치 예측하여 채워넣는 방식

결측치 모델의 주의사항

  • 대부분의 상황에서 활용이 가능하지만, 사용 조건과 단점을 고려해야 합니다.

  • 사용 조건 및 단점

image

관련 문법 : sklearn.impute.KNNImputer


  • 결측치가 아닌 값만을 사용하여 이웃을 구한 뒤, 이웃인 값들의 대표값으로 결측을 대체하는 결측치 예측 모델

파라미터

  • n_neighbors : 이웃의 수 (너무 값이 작으면 결측 대체가 정상적으로 이뤄지지 않는다. 보통 5를 많이 사용한다.)

image


  • 1) 결측이 발생한 인덱스 a, c, d에 대한 이웃을 찾습니다.

  • 2) 이웃을 찾는 방식 :

    • c의 이웃값 찾기 => 인덱스 c, d에서 결측이 없는 V2의 값으로 판단 -> V2의 인덱스 d와 c의 거리 : (7-5) = 2

    • b의 이웃값 찾기 => 인덱스 b, d에서 결측이 없는 V2의 값으로 판단 -> V2의 인덱스 d와 b의 거리 : (7-4) = 3

    • d의 이웃값 찾기 => 인덱스 d, e에서 결측이 없는 V2의 값으로 판단 -> V2의 인덱스 d와 e의 거리 : (7-2) = 5

  • 3) 이웃값들의 대표값 찾기

    • d의 이웃값은 c와 b입니다. 하지만 c는 NaN이므로 대표값이 되는 b의 2가 입력됩니다.

    • c의 이웃값은 b와 e입니다. 따라서 2와 3의 평균값인 2.5가 입력됩니다.

이 코드는 필수 라이브러리를 불러오고, 불필요한 경고 메시지를 숨기며, 현재 작업 경로를 설정하는 과정을 담고 있습니다. ospandas 라이브러리를 임포트하여 파일 시스템 작업과 데이터 처리 기능을 사용할 수 있게 합니다. warnings.filterwarnings(action = 'ignore')를 통해 경고 메시지를 무시하도록 설정합니다. 마지막으로, %pwd 매직 커맨드를 사용해 현재 작업 경로를 얻고, os.chdir(a)를 통해 이 경로를 작업 디렉토리로 설정합니다.

1
2
3
4
5
6
7
8
9
import os
import pandas as pd

# 불필요한 경고 표시를 생략합니다.
import warnings
warnings.filterwarnings(action = 'ignore')

a=%pwd # 현재 작업 경로를 변수 a에 할당합니다.
os.chdir(a) # 현재 작업 경로로 파일 로드 경로를 설정합니다.

pd.read_csv("mammographic.csv") 함수는 mammographic.csv 파일을 읽어서 pandas의 DataFrame 객체로 변환합니다. 이 과정을 통해 데이터를 분석 및 처리할 수 있는 형태로 로드합니다.

1
df = pd.read_csv("mammographic.csv") # mammographic.csv 파일을 읽어서 DataFrame으로 변환

이 함수는 데이터프레임에서 특징과 라벨을 분리합니다. df.drop('Output', axis = 1)를 사용하여 ‘Output’ 열을 제외한 모든 열을 X에 할당하고, df['Output']을 사용하여 ‘Output’ 열만 Y에 할당합니다. 이 과정은 머신러닝 모델을 학습시키기 전에 입력 변수와 타겟 변수를 분리하는 데 사용됩니다.

1
2
3
# 특징과 라벨 분리
X = df.drop('Output', axis = 1)  # 'Output' 열을 제외한 모든 열을 X에 할당
Y = df['Output']  # 'Output' 열만 Y에 할당

이 함수는 train_test_split을 사용하여 데이터를 학습 데이터와 평가 데이터로 분리합니다. train_test_split 함수는 sklearn.model_selection 모듈에 포함되어 있으며, 데이터셋을 무작위로 학습 세트와 테스트 세트로 나눕니다. 이 과정은 모델을 학습시키기 위한 데이터와 모델의 성능을 평가하기 위한 데이터를 준비하는 데 필수적입니다.

1
2
3
# 학습 데이터와 평가 데이터 분리
from sklearn.model_selection import train_test_split
Train_X, Test_X, Train_Y, Test_Y = train_test_split(X, Y)

이 함수는 Train_X 데이터프레임 내의 각 열별 결측치의 비율을 계산합니다. isnull().sum()을 사용하여 각 열의 결측치 수를 구하고, len(Train_X)으로 전체 행의 수로 나누어 결측치의 비율을 확인합니다. 이를 통해 데이터의 결측치가 상대적으로 적은지 여부를 판단할 수 있습니다.

1
2
# 열별 결측치 비율 확인 => 그리 높지 않음을 확인
Train_X.isnull().sum() / len(Train_X)

이 함수는 Train_X 데이터프레임의 모든 특징(열) 간의 상관 계수를 계산하고, 그 합을 특징의 총 수로 나누어 평균 상관 계수를 구합니다. 결과적으로, 이는 Train_X 내 특징들이 서로 얼마나 강하게 연관되어 있는지를 나타내는 지표로 활용됩니다. 평균 상관 계수가 약 40 ~ 50%로 매우 높다는 주석은, 데이터 내 변수들이 서로 중요한 관계를 가지고 있음을 시사합니다.

1
2
# 특징 간 상관 계수 확인 => 평균적으로 약 40 ~ 50%로 매우 높음
Train_X.corr().sum() / len(Train_X.columns)

KNN Imputer


단계별로 생각해 봅시다.

이 함수는 KNNImputer 클래스를 사용하여 결측치를 대체합니다. 먼저, KNNImputern_neighbors=5로 설정하여 모델을 생성합니다. 그 후, fit 메소드를 사용하여 훈련 데이터(Train_X)에 모델을 학습시킵니다. 마지막으로, transform 메소드를 사용하여 훈련 및 테스트 데이터셋(Train_X, Test_X)의 결측치를 인접한 5개 이웃의 값으로 대체하고, 결과를 데이터프레임으로 변환하여 열 이름을 유지합니다.

1
2
3
4
5
6
7
8
9
10
# KNN Imputer 모델 생성
from sklearn.impute import KNNImputer
KI = KNNImputer(n_neighbors = 5)

# KNN Imputer 학습
KI.fit(Train_X)

# 결측 대체
Train_X = pd.DataFrame(KI.transform(Train_X), columns = Train_X.columns)
Test_X = pd.DataFrame(KI.transform(Test_X), columns = Test_X.columns)

이 함수는 Train_X 데이터프레임 내의 각 열에 대해 결측치의 비율을 계산합니다. isnull().sum()을 사용하여 각 열의 결측치 수를 구하고, len(Train_X)으로 데이터프레임의 전체 행 수로 나누어 결측치의 비율을 구합니다.

1
2
# Train_X 데이터프레임에서 결측치의 비율을 계산합니다.
Train_X.isnull().sum() / len(Train_X)

이 함수는 Test_X 데이터프레임에서 각 열별 결측치의 비율을 계산합니다. isnull() 메서드를 사용하여 각 셀이 결측치인지 여부를 확인하고, sum() 메서드로 각 열별 결측치의 총 수를 계산합니다. 그 후, len(Test_X)를 사용하여 Test_X의 전체 행 수로 나누어 각 열별 결측치의 비율을 구합니다.

1
Test_X.isnull().sum() / len(Test_X)  # Test_X 데이터프레임에서 각 열별로 결측치의 비율을 계산합니다.

댓글남기기