데이터 분석에서 결측치 처리는 중요한 단계입니다. 이 글에서는 pandas 라이브러리를 활용한 결측치 처리 방법과 데이터 전처리 전략을 소개합니다. 결측치 문제를 해결하여 데이터의 품질을 향상시키는 데 도움이 될 것입니다.
주요내용
- 📊 데이터 전처리의 중요한 부분인 결측치 처리 방법에 대해 배웁니다.
- 🛠 pandas 라이브러리의
isnull
,dropna
함수를 사용하여 결측치를 식별하고 처리하는 방법을 알아봅니다. - 📈 결측치 비율을 계산하고, 데이터의 품질을 유지하면서 결측치를 효과적으로 처리하는 전략을 배웁니다.
이 코드는 필요한 라이브러리를 불러오고, 불필요한 경고 메시지를 숨기며, 현재 작업 경로를 설정하는 과정을 담고 있습니다. os
와 pandas
라이브러리를 임포트하고, warnings
모듈을 사용해 경고 메시지를 필터링합니다. 그 후, 매직 커맨드 %pwd
를 사용해 현재 작업 경로를 변수 a
에 할당하고, 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) # 현재 작업 경로로 파일 로드 경로를 설정합니다.
결측치 문제?
-
데이터에 결측치가 있어, 모델의 학습이 되지 않는 문제
-
결측치는 보통 NaN 과 None로 구분된다.
-
NaN : 값이 있어야 하는데 없는 결측치 -> 보통 대체, 추정, 예측 등으로 처리한다.
-
None : 값이 없는 것 자체가 value인 결측치 -> 보통 새로운 값으로 정의(예: 직업 - 백수)하는 방식으로 처리
-
-
결측치를 처리하는 방법은 간단하다. 하지만
상황에 맞는 적절한 처리
가 결측치 문제의 포인트이다. -
경우에 따라서는 음수값이 없는 경우 ‘-1’을 입력해 해당 데이터가 포함되지 않도록 하는 방식의 전처리 법도 있다.
결측 레코드
-
결측치를 포함하는 레코드(data)를 의미
-
결측치 비율 : 결측 레코드 수 / 전체 레코드 수
-
결측 레코드: #1, #3, #5, #8
-
결측치 비율: 결측 레코드 수(4개) / 전체 레코드 수(10개)
-
변수별 결측치 비율
-
v1: 1 / 10 = 0.1
-
v2: 2 / 10 = 0.2
-
v3: 1 / 10 = 0.1
-
v4: 1 / 10 = 0.1
-
v5: 2 / 10 = 0.2
-
일반적으로 결측치 비율이 30%(0.3) 이상인 경우 결측치 비율이 높다고 판단한다
- 단, 무조건적으로 이 비율을 맹신하지 말고, 데이터의 샘플 수에 따라 적절히 판단할 필요가 있다.
관련 함수 1 : Series / DataFrame.isnull()
-
값이 결측이면 True, 결측이 아니면 False를 반환합니다. (notnull 함수와 반대)
-
단순히 isnull만 사용하면 정확한 개수 확인이 어려움 -> isnull.sum() 으로 결측치 분포 확인하는데 활용
관련 함수 2 : DataFrame.dropna()
- 결측치가 포함된 행이나 열을 제거하는 함수
파라미터
-
axis = 1 은 결측이 포함된 ‘열’을 삭제
-
axis = 0 은 결측이 포함된 ‘행’을 삭제
-
how = ‘any’는 결측이 1개라도 있으면 해당 레코드를 삭제 (일반적으로 사용)
-
how = ‘all’은 모든 값이 결측인 경우에만 해당 레코드를 삭제
결측치 삭제
-
결측치 삭제는 항상
Train data
를 기준으로 하는 전처리 작업이다. -
따라서 샘플 데이터를 X(변수), Y(레이블)로 나누고, train 데이터와 test 데이터로 나눈 후에 전처리를 한다.
-
Train data에 전처리 작업을 해주었다면, 동일 기준으로 Test data에도 전처리 작업을 해주어야 한다.
행 단위 삭제
- 2가지 조건을 만족하는 경우에만 삭제를 할 수 있다.
이 함수는 pandas
라이브러리의 read_csv
함수를 사용하여 "mammographic.csv"
파일에서 데이터를 불러오고, 불러온 데이터를 df
변수에 저장합니다. 이후 df
를 출력하여 불러온 데이터를 확인할 수 있습니다.
1
2
3
4
# 데이터 불러오기
# mammographic.csv 파일에서 데이터를 불러옵니다.
df = pd.read_csv("mammographic.csv")
df
본 코드는 데이터프레임 df
에서 ‘Output’ 열을 제외한 모든 열을 X
에 할당하고, ‘Output’ 열만을 Y
에 할당합니다. 이 과정은 머신러닝 모델에서 입력 특징과 예측 대상 라벨을 분리하는 표준 절차를 따릅니다.
1
2
3
# 특징과 라벨 분리
X = df.drop('Output', axis = 1)
Y = df['Output']
train_test_split
함수는 데이터를 학습 데이터와 평가 데이터로 분할합니다. 이 함수는 sklearn.model_selection
모듈에 포함되어 있으며, 입력 데이터(X
)와 타겟 데이터(Y
)를 받아 네 부분으로 나눕니다: 학습 데이터의 특성(Train_X
), 테스트 데이터의 특성(Test_X
), 학습 데이터의 타겟(Train_Y
), 그리고 테스트 데이터의 타겟(Test_Y
).
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(axis=0)
을 통해 열별로 결측치의 총 개수를 합산합니다.
1
Train_X.isnull().sum(axis = 0) # 열별 결측치 개수 확인
이 코드는 데이터프레임 Train_X
내의 각 열별 결측치 비율을 계산합니다. 결측치가 전체적으로 많지 않음에도 불구하고, 모든 컬럼에 최소 한 번 이상 결측치가 발생하기 때문에 열을 삭제하는 것은 적절하지 않습니다. 대신, 결측치가 포함된 행을 삭제하는 것이 일반적인 처리 방법으로 제시됩니다.
1
2
3
4
Train_X.isnull().sum(axis = 0) / len(Train_X) # 열별 결측치 비율 확인
# 결측치가 전체적으로 많지 않으나, 모든 컬럼에 결측치가 최소 한 번 이상 발생하여 열 삭제는 불가능합니다.
# 이 경우, 결측치가 있는 '행'을 모두 삭제하는 방법이 가장 일반적입니다.
Train data의 결측치 제거
FORMAT:
{“markdown”: “string”}
단계별로 생각해 봅시다.
Train_X.dropna(inplace = True)
함수는 Train_X
데이터프레임에서 결측치가 포함된 레코드를 제거합니다. inplace=True
파라미터는 변경사항을 원본 데이터프레임에 바로 적용하며, 별도의 할당 과정 없이 원본 데이터를 수정합니다.
1
Train_X.dropna(inplace = True) # 결측치가 포함된 레코드를 제거합니다.
Test data의 결측치 제거
단계별로 생각해 봅시다.
Test_X.dropna(inplace = True)
는 데이터프레임 Test_X
에서 결측치를 포함하는 모든 레코드를 제거합니다. inplace=True
파라미터는 변경사항을 원본 데이터프레임에 바로 적용함을 의미합니다. 이 작업은 새로 들어온 데이터에 대한 결측치 처리를 포함하지 않으므로, 새 데이터를 처리하기 전에 결측치가 없는지 확인해야 합니다.
1
Test_X.dropna(inplace = True) # 결측치가 포함된 레코드 제거 (주의: 새로 들어온 레코드의 결측치가 있으면 처리하지 못함을 의미)
열 단위 삭제
- 마찬가지로 2가지 조건을 만족하는 경우에만 삭제할 수 있습니다.
1) 소수 변수에 결측이 많이 포함되어 있을 때 (예: sample이 1만개인데, 한 컬럼에만 결측치가 몇천 개인 경우)
2) 해당 변수들이 크게 중요하지 않을 때 (도메인 지식으로 판단)
이 함수는 pd.read_csv()
를 사용하여 "post_operative.csv"
파일에서 데이터를 불러온 후, df.head()
를 통해 불러온 데이터프레임의 처음 5행을 출력합니다. pd
는 일반적으로 pandas 라이브러리의 축약형으로 사용됩니다. 이 코드는 데이터 분석 초기 단계에서 데이터를 불러오고, 데이터의 구조를 빠르게 확인하기 위한 기본적인 절차를 보여줍니다.
1
2
3
4
5
# 데이터 불러오기
# post_operative.csv 파일에서 데이터를 읽어옵니다.
df = pd.read_csv("post_operative.csv")
# 데이터의 처음 5행을 출력합니다.
df.head()
본 코드는 데이터프레임 df
에서 ‘Decision’ 열을 제외한 모든 열을 X
에 할당하고, ‘Decision’ 열만을 Y
에 할당합니다. 이 과정은 머신러닝 모델에서 특징(features)과 라벨(labels)을 분리하는 표준 절차를 따릅니다.
1
2
3
# 특징과 라벨 분리
X = df.drop('Decision', axis = 1)
Y = df['Decision']
train_test_split
함수는 데이터를 학습 데이터와 평가 데이터로 분할합니다. 이 함수는 sklearn.model_selection
모듈에 포함되어 있으며, 입력 데이터(X
)와 타겟 데이터(Y
)를 받아 학습 데이터(Train_X
, Train_Y
)와 평가 데이터(Test_X
, Test_Y
)로 나눕니다.
1
2
3
# 학습 데이터와 평가 데이터 분할
from sklearn.model_selection import train_test_split
Train_X, Test_X, Train_Y, Test_Y = train_test_split(X, Y)
이 함수는 데이터 프레임의 상위 5개 행을 출력하여 COMFORT
변수에 ‘?’ 문자로 표시된 결측치를 확인합니다. 이후, 결측치가 특정 문자로 표현된 경우 해당 데이터를 삭제하는 작업을 수행합니다.
1
2
3
Train_X.head() # COMFORT 변수에 '?'로 결측이 표시되어 있음을 확인
# 결측치가 별도의 문자로 표현된 경우 삭제
운이 좋게 head()
로 ?를 발견했지만, 그렇지 않을 경우도 있으므로 항상 unique()
함수를 통해 각 컬럼의 값들을 확인해 보는 것이 좋다.
Train_X['COMFORT'].unique()
함수는 Train_X
데이터프레임의 'COMFORT'
열에 포함된 고유값들을 추출합니다. 이는 데이터 전처리나 분석 단계에서 해당 열의 다양성을 파악하는 데 유용하게 사용됩니다.
1
Train_X['COMFORT'].unique() # Train_X 데이터프레임의 'COMFORT' 열에서 고유값을 추출합니다.
이 함수는 numpy
모듈을 사용하여 Train_X
데이터셋 내의 결측치 비율을 계산합니다. 결측치는 '?'
로 표시되며, 이를 np.nan
으로 대체한 후 전체 데이터셋 길이에 대한 결측치의 비율을 계산합니다. 이 과정은 데이터 전처리 단계에서 중요하며, 데이터에 대한 충분한 이해 없이는 적절한 처리가 어려울 수 있음을 강조합니다.
1
2
3
4
5
# 결측치 비율 확인
import numpy as np
# 결측이 '?'로 표시되어 있음 => 데이터에 대한 이해가 없으면 적절한 처리가 어려울 수 있음
Train_X.replace('?', np.nan).isnull().sum() / len(Train_X)
이 코드는 데이터 전처리 과정에서 특정 변수의 중요성과 결측값 처리를 다룹니다. Train_X
데이터셋에서 결측값이 있는 모든 컬럼을 삭제하며, 이는 COMFORT
변수가 중요하지 않다는 가정 하에 수행됩니다. 이후, 일관성을 유지하기 위해 Test_X
데이터셋에서도 COMFORT
변수를 삭제합니다. 또 다른 접근으로, Train_X
의 컬럼을 기준으로 Test_X
데이터셋을 업데이트하는 방법이 제시되어 있으나, 이는 주석 처리되어 있습니다.
1
2
3
4
5
6
7
8
9
10
11
# COMFORT 변수에 결측값이 집중되어 있고, 이 변수가 중요하지 않다고 판단되어 삭제
Train_X.dropna(axis = 1, inplace = True)
# Test_X에서 COMFORT 변수를 삭제, COMFORT에 결측값이 없더라도 일관성을 위해 삭제
Test_X.drop('COMFORT', axis = 1, inplace = True)
# 방법 2
# Train_X에서 이미 삭제된 상태이므로, Train_X의 컬럼과 동일하게 Test_X를 업데이트
# Test_X = Test_X[Train_X.columns]
이 함수는 Train_X
데이터프레임에서 각 열별로 결측값의 총합을 계산합니다. isnull()
메소드를 사용하여 각 셀이 결측값인지 여부를 확인하고, sum(axis=0)
을 통해 열별로 결측값의 개수를 합산합니다.
1
2
# 결과 확인
Train_X.isnull().sum(axis = 0)
댓글남기기