[2주차] 결측치와 누락값

2024. 1. 7. 21:19Portfolio/BDA 7기

Contents 접기

결측치와 누락값

결측치와 누락값은 데이터 분석에서 중요한 요소로 간주된다.

 

결측치는 실제로 값이 없는 상황,

누락값은 휴먼 에러 등으로 인해 빠진 값이다. 

둘 다 " 값이 없다"는  NA, NaN과 같은 표현으로 나타낼 수 있다.

 

 

순수한 결측치 vs na값 자체가 값인 경우

예를 들어, 설문조사에서 "가장 선호하는 색깔은?" 이라는 질문에 대답하지 않은 경우 해당 값은 결측치가 된다.

이는 데이터에서 값이 실제로 빠져있어서 해당 위치에 아무런 정보가 없는 경우를 의미한다.

 

반면, 통신이나 센서 데이터에서 "na"값은 신호 강도가 부족하거나 데이터의 품질이 낮은 상태를 나타낸다.

이 경우, "na"값은 특별한 상태를 나타내는 것!

 

 

결측치 & 누락값을 왜 처리하여야 하는가?

데이터의 정확성과 분석 결과의 신뢰성 유지를 결정하기 때문이다.
na값이 의미있는 값인 경우 인사이트가 될 수 있다.

그러므로 결측치는 중요하고, 단순하게 접근하는 범위가 아니다.

결측치를 실제값과 유사하지 않게 적는다면, 결국 차이가 발생하고 모델의 성능에도 영향을 미친다.

 

 

그렇다면 이런 결측치를 처리하는 방법은?

 

가장 간단한 방법은 결측치를 제거하는 것이다.

결측치를 제거하는 기준은 전체 데이터 셋에서 결측치가 차지하는 비중에 따라 달라지며,

무조건 제거하는 것은 머신에게 학습시킬 데이터양이 줄어들어 성능에 영향을 줄 수 있다.

따라서 결측치를 최대한 채워서 메꾸는 형식을 생각해야 한다.

 

다음은 결측치 처리하는 과정에서 발생할 수 있는 문제점이다.

결측치를 다 제거할 경우, 막대한 데이터 손실 가능성
결측치를 잘못 대체할 경우, 데이터 편항(bias) 가능성
결측치를 처리하는 과정에서, 분석가 주관으로 인한 편항(bias) 발생 가능성 

 

 

결측치의  3가지 유형

완전 무작위 결측치(Missing Completely At Random, MCAR)

 

인간의 편향이나 기계 결함과 같은 다른 변수와 상관 없이 완전 무작위 랜덤한 경우

ex) 전산, 통신문제 등으로 인한 데이터 누락

 

무작위 결측(Missing At Random, MAR)

 

결측값의 발생이 특정 변수와 관련이 있으나 얻고자 하는 결과와는 상관이 없을 경우

ex) 30대 남성이 용돈 설문을 할 때 결측값이 자주 발생하여 30대 남성과 용돈 설문 결측에는 관련이 있음.

하지만, 얻고자 하는 결과(소득수준)과 용돈 설문과는 상관관계가 없을 경우

 

비무작위 결측(Missing Not At Random, MNAR)

 

결측값 발생이 다른 변수와 상관이 있는 경우

ex) 소득이 적은 사람이 소득에 대한 결측값을 가지기 쉽다면(자기 소득을 밝히기 싫어한다는 가정),

이 데이터는 비무작위 결측

 


 

데이터를 불러와서 결측치를 확인해보자

# 데이터 불러와서 결측치 보기

import missingno as msno # 결측치 시각화
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

df = pd.read_csv('bike_sharing_daily.csv')
dfe = pd.read_csv('country_timeseries.csv') # 시계열 데이터

df.isna().sum() # na값 몇 개인지 확인

 

instant 0
dteday 0
season 0
yr 0
mnth 0
holiday 0
weekday 0
workingday 0
weathersit 0
temp 17
atemp 24
hum 25
windspeed 13
casual 11
registered 11
cnt 0
dtype: int64

 

결측치를 가지고 있는 변수를 확인했고, 이를 바탕으로 시각화를 진행해보자

# 결측치 시각화
msno.matrix(df) # 결측치 히트맵 시각화
plt.show() # msno.matrix(df) 그래프를 실제 화면에 출력하는 역할

결측치 히트맵

 

히트맵에서 중간에 선 스펙트럼처럼 중간중간 비워져 있는 부분이 결측치를 표현한 것이다.

그러나, 결측치의 정확한 개수를 파악하기 어려우므로 막대그래프로 표현해보자.

# 막대그래프
msno.bar(df)
plt.show()

결측치 막대그래프로 시각화

 

히트맵과 달리 전체 731개의 데이터 중 결측치를 제외한 개수와 막대의 높낮이로 결측치의 비교가 용이해졌다.

 

 

결측치 처리 방법

결측치 처리 방법에는 크게 3가지로 볼 수 있다.

1. 제거
2. 평균, 중위값 등 특정 통계 값으로 대체
3. 보간법(Interpolation)

 

 

1. 결측치 제거

 

샘플 데이터만 뽑아서 어떤 식으로 작동하는지 확인해보자

# 결측치가 어떤 식으로 바뀌는지 확인
ebola = dfe.iloc[0:30, 0:5]
ebola.dropna() # 결측치 포함 데이터 제거

결측치가 제거된 데이터

 

2. 특정 통계 값으로 대체
fillna(method=") # 결측치를 ()안의 값으로 대체
ebola['Cases_Liberia'].mean() # case liberia의 mean = 7496.411764705882
ebola['Cases_Liberia'].fillna(7496.411764705882).to_frame() # 결측치를 평균으로 대체

결측치가 평균값으로 대체

 

fillna() 함수를 사용하여 결측치를 처리하더라도, 이는 기본적으로 해당 연산을 수행한 복사본을 반환하며,

원본 데이터에 직접 영향을 주지 않는다.

 

결측치의 앞, 뒤 데이터를 이용하여 결측치를 대체하는 방법도 있다.

# ffill - 누락값이 나타나기 전의 값으로 누락값 변경
ebola['Cases_Liberia'].fillna(method='ffill').to_frame()

# bfill - 누락값 이후의 첫 번째 값으로 앞쪽의 누락값 변경
ebola['Cases_Liberia'].fillna(method='bfill').to_frame()

원본 데이터                                                              method = 'ffill'                                                       method = 'bfill'

 

3. 보간법 (interpolate)

 

누락값 사이의 값을 평균으로 대체해서 만든다.

중간에 결측치가 있으면 보간법을 이용해서 결측치를 대체한다.

# 보간법
ebola['Cases_Liberia'].interpolate().to_frame()

전후 평균으로 대체

 

 

보간법의 종류

보간법은 여러가지 method가 존재한다.

# 다양한 보간법 method
['linear', 'time', 'index', 'values', 'nearest', 'zero', 'slinear', 'quadratic', 'cubic', 'barycentric', 'krogh', 'spline', 'polynomial', 'from_derivatives', 'piecewise_polynomial', 'pchip', 'akima', 'cubicspline']

 

plot 그래프를 통해 다양한 보간법에 따라 시각화 결과의 차이를 비교해보자

# 결측값이 있는 경우는 뚝 떨어진 값이 된다.
ebola['Cases_Liberia'].plot()

# 선형(Linear)보간법
# 1차원 두 점 사이의 거리로 해당 누락값 대체
ebola['Cases_Liberia'].interpolate(method='Linear').plot()

# 2차로 항을 높여 보간
ebola['Cases_Liberia'].interpolate(method='slinear').plot()

# 3차로 항을 높여 보간
ebola['Cases_Liberia'].interpolate(method='cubic').plot()

 

 

 

linear 보간과 같이 1차원 차원으로 생각해서

데이터 포인트를 직선으로 이어 결측치를 채우며 보간할 수 있지만,

spline 보간을 통해 order 차수를 높여 2차원 이상의 곡선 형태의 비선형적인 패턴으로 보간할 수 있다. 

# spline 보간
ebola['Cases_Liberia'].interpolate(method='spline', order=2).plot()

spline 2차 보간

 

시계열 데이터 보간

 

시계열 데이터의 보간에서는 시간 간격에 따라 데이터를 선형적으로 보간한다.

선형적인 보간은 알려진 두 개의 데이터 포인트(결측치 전, 후)를 사용하여 결측치를 추정한다.

dfe['Date']=pd.to_datetime(dfe['Date']) # 'Date'열을 날짜 형식으로 변환
df_e = dfe.set_index('Date') # 인덱스 설정, 날짜별로 데이터에 접근 용이해짐

# 시간에 따른 결측치 대체
df_e.iloc[0:30,0:5]['Cases_Liberia'].interpolte(method='time').to_frmae()

method = 'time'