다운로드
작성자: donotgetgreed@gmail.com 작성일시: 2018-10-27 06:57:22 조회수: 544 다운로드: 45
카테고리: 기타 태그목록:

누락 데이터 처리

실제로 현업에서 사용하는 데이터는 책에서 예제로 쓰는 데이터들 처럼 모든 데이터가 잘 들어가 있는 경우가 거의 없다. 값이 잘못된 경우, 데이터 타입이 잘못된 경우, 데이터가 없는 경우 등 데이터를 분석하는 사람으로써 난감한 상황들이 자주 발생한다. 이 중 데이터가 없는 경우, 이 누락된 데이터 부분을 누락데이터라고 한다. 이번 절에서는 누락데이터가 왜 발생하며 어떻게 처리를 해야하는지에 대해 학습 할 것이다.

누락 데이터의 종류

누락 데이터는 MCAR(Missing completely at random)과 MAR(Missing at random) 그리고 MNAR(Missing at not random)으로 나눌 수 있다.

  • MCAR : MCAR은 변수의 종류와 변수의 값과 상관없이 전체에 걸쳐 무작위적으로 나타나는 것으로 이러한 누락 데이터는 분석에 큰 영향을 주지는 않는다. 실제로 MCAR의 경우는 거의 없다.
  • MAR : 누락된 자료가 특정 변수와 관련되어 일어나지만 그 변수의 값과는 관계가 없는 경우이다. 예를 들어 어떤 설문조사에서 누락된 자료가 특정 변수들에 국한되어 발견되었는데 알고 보니 일부 대상자가 설문지 3페이지에 반대쪽 면이 있는 것을 모르고 채우지 않았을 경우 MAR로 볼 수 있다.
  • MNAR : 누락된 변수의 값과 누락된 이유가 관련이 있는 경우이다. 예를 들어 노인에서 우울증에 대한 설문조사를 했는데 실제로 우울증이 심한 경우는 우울한 기분에 대해 자세히 조사하는 항목을 대답하는 것이 괴로워 일부러 회피하여 누락되는 경우 등이다. 일부 설문에 정치적인 이유로 일부러 대답을 회피하거나 하는 경우도 MNAR로 볼수 있다.

수치적 데이터의 누락데이터 표현

먼저 아래의 설명을 도와줄 데이터를 불러온다. 불러올 데이터는 airquality 데이터 셋으로 1973년 5월 부터 9월까지의 뉴욕의 대기에 대한 정보를 담고 있다.

각 열의 의미

  • Ozone: 평균 오존 농도
  • Solar.R: 일광량
  • Wind: 평균 풍속
  • Temp: 최대 기온(화씨)
  • Month: 해당 월
  • Day: 해당 날짜
In [1]:
airquality = sm.datasets.get_rdataset("airquality", package="datasets")
airquality_df = airquality.data
airquality_df.tail()
Out:
Ozone Solar.R Wind Temp Month Day
148 30.0 193.0 6.9 70 9 26
149 NaN 145.0 13.2 77 9 27
150 14.0 191.0 14.3 75 9 28
151 18.0 131.0 8.0 76 9 29
152 20.0 223.0 11.5 68 9 30

수치적 데이터에 대한 누락데이터는 NaN(Not a Number) 값으로 표현한다.

In [2]:
print(airquality_df.Ozone[4])
nan

만약 수치적 데이터에 대한 누락 데이터가 0,혹은 다른 값으로 저장되어 있다면, 해당 데이터의 통계량에 큰 영향을 미치게 된다. 이 때문에 누락데이터를 NaN 값으로 두어 통계량을 계산 할 때 제외시키도록 한다. pandas DataFrame의 fillna()를 사용하면, NaN 값을 지정한 값으로 교체 할 수 있다. 다음 코드를 통해서 결측치를 0으로 했을 때 바뀌는 통계량을 확인한다.

In [3]:
airquality_df.Ozone.mean(), airquality_df.Ozone.fillna(0).mean()
Out:
(42.12931034482759, 31.941176470588236)

그리고 반드시 알아두어야 하는 것은 NaN은 실수형 데이터 라는 것이다.

In [4]:
print(type(airquality_df.Ozone[4]))

리스트가 아닌 배열은 내부에 같은 종류의 데이터만 담을 수 있다. Pandas의 열 또한 하나의 배열이므로, 그 열의 원 데이터는 정수(int)라 하더라도, 그 열에 NaN 값이 들어가면, 모든 데이터가 실수형 데이터가 된다. airquality 데이터의 일광량 데이터를 보면, 모든 숫자들의 소숫점 부분이 모두 0으로 되어 있다. 이는 사실 측정 단위는 정수였지만, NaN 값 때문에 전체 데이터가 실수형 자료가 되었다는 것을 유추해 볼 수 있겠다.

In [5]:
airquality_df["Solar.R"][:5]
Out:
0    190.0
1    118.0
2    149.0
3    313.0
4      NaN
Name: Solar.R, dtype: float64

외부의 데이터를 불러오거나 다운로드 받아서 열어보면 한 열 안에 여러 개의 자료형이 담겨 있는 경우가 있다. 문제가 없어 보이지만 나중에 분석을 할 때 에러가 발생 할 것이다. 만약 가져온 데이터가 그렇다면, 한 열의 데이터 타입을 직접 추론하여 맞추어주어야 한다. 다음에 불러올 데이터는 attenu 데이터셋으로 캘리포니아에서 발생한 23번의 지진에 대해 여러 관측소에서 관측한 지진파를 기록한 것이다.

각 열의 의미는 다음과 같다.

  • event : 각 지진을 1 ~ 23번으로 표현
  • mag : 해당 지진의 진도
  • station : 관측소의 식별자
  • dist : 진원지로 부터 관측소사이의 거리(km)
  • accel : 지진파의 최대 진동 (g)
In [6]:
attenu = sm.datasets.get_rdataset("attenu", package="datasets")
attenu_df = attenu.data
attenu_df.tail()
Out:
event mag station dist accel
177 23 5.3 c266 46.1 0.070
178 23 5.3 c203 47.1 0.080
179 23 5.3 5069 47.7 0.033
180 23 5.3 5073 49.2 0.017
181 23 5.3 5072 53.1 0.022

이 데이터의 station 열에는 문자열 데이터와 실수형 데이터(NaN)가 같이 있다.

In [7]:
print(attenu_df.station[154], type(attenu_df.station[154]))
nan 
In [8]:
print(attenu_df.station[153], type(attenu_df.station[153]))
1219 

그리고, NaN 값에 대해 알아 둘 점이 하나 더 있다. 다음 코드의 결과를 보자.

In [9]:
attenu_df.station[154] == float("NaN")
Out:
False

분명 같은 NaN 값 임에도, False가 출력된다. NaN값은 이렇게 직접 비교가 안된다는 것을 기억 해두자.

누락데이터의 시각화

데이터의 크기가 크면 어디에 누락데이터가 분포해 있는지 확인하기 힘들다. 이 때는 시각화를 통해 전체적인 누락데이터의 분포를 확인 할 수 있다. Missingno 패키지를 사용하면 누락데이터에 대한 시각화를 쉽게 할 수 있다.

설치

  • pip install missingno

예제를 위한 데이터 셋을 불러오겠다. 여기서는 Quilt 라는 데이터 관리 패키지 사용한다. Quilt는 데이터를 코드 처럼 버전 관리 할 수 있도록 해주는 도구이다.

설치

  • pip install quilt

데이터를 사용하려면, 다음과 같이 먼저 데이터를 다운로드 받아야 한다.

In [10]:
!quilt install ResidentMario/missingno_data
Downloading package metadata...
ResidentMario/missingno_data already installed.
Overwrite? (y/n) ^C

In [11]:
from quilt.data.ResidentMario import missingno_data
In [12]:
collisions = missingno_data.nyc_collision_factors()
collisions = collisions.replace("nan", np.nan)
collisions.set_index("Unnamed: 0", inplace=True)
In [13]:
collisions.tail(3)
Out:
DATE TIME BOROUGH ZIP CODE LATITUDE LONGITUDE LOCATION ON STREET NAME CROSS STREET NAME OFF STREET NAME ... CONTRIBUTING FACTOR VEHICLE 1 CONTRIBUTING FACTOR VEHICLE 2 CONTRIBUTING FACTOR VEHICLE 3 CONTRIBUTING FACTOR VEHICLE 4 CONTRIBUTING FACTOR VEHICLE 5 VEHICLE TYPE CODE 1 VEHICLE TYPE CODE 2 VEHICLE TYPE CODE 3 VEHICLE TYPE CODE 4 VEHICLE TYPE CODE 5
Unnamed: 0
7300 01/04/2016 17:45:00 BROOKLYN 11235.0 40.581744 -73.953836 (40.5817444, -73.9538363) SHORE BOULEVARD CASS PLACE NaN ... Failure to Yield Right-of-Way Unspecified NaN NaN NaN PASSENGER VEHICLE PASSENGER VEHICLE NaN NaN NaN
7301 01/02/2016 17:20:00 MANHATTAN 10016.0 40.750960 -73.982723 (40.7509597, -73.9827227) WEST 38 STREET 5 AVENUE NaN ... Lost Consciousness Lost Consciousness NaN NaN NaN PASSENGER VEHICLE TAXI NaN NaN NaN
7302 01/02/2016 20:00:00 BROOKLYN 11213.0 40.663604 -73.934391 (40.6636039, -73.9343912) SCHENECTADY AVENUE EMPIRE BOULEVARD NaN ... Lost Consciousness Unspecified NaN NaN NaN SPORT UTILITY / STATION WAGON PASSENGER VEHICLE NaN NaN NaN

3 rows × 26 columns

방금 불러온 데이터 셋에는 다음과 같이 많은 누락데이터가 존재한다. Missingno 패키지를 활용하면 다음과 같이 누락데이터에 대한 시각화가 가능하다. matrix()명령은 매트리스 형태로 누락데이터를 시각화 하는 명령이다. 오른쪽의 표현되는 것은 스파크라인(spark line)이라고 부르고, 각 행의 데이터 완성도를 표현한다. 만약 데이터셋의 전체 열의 갯수가 26개 이고, 해당 행에, 2개의 열에 대한 누락데이터가 존재 한다면, 그 행의 스파크라인은 24이다. 스파크라인에는 데이터 완성도의 최댓값과 최솟값이 표시되어 있다.

In [14]:
import missingno as msno

msno.matrix(collisions)
plt.show()

만약 각 열의 누락데이터가 얼마나 존재하는지에 대해서만 시각화 하고 싶다면, bar()명령을 사용하면 된다.

In [15]:
msno.bar(collisions)
plt.show()