다운로드
작성자: admin 작성일시: 2019-10-20 15:09:59 조회수: 5191 다운로드: 176
카테고리: 머신 러닝 태그목록:

2.1 데이터 전처리 기초

이 절에서는 데이터를 본격적으로 분석하기 이전에 다음과 같은 패키지를 사용하여 기초적인 전처리(preprocessing)를 하는 방법을 설명한다.

  • missingno 패키지: 결측 데이터 검색
  • sklearn.impute 패키지: 결측 데이터 대체
  • patsy 패키지: 데이터 선택, 변환, 추가, 스케일링
  • sklearn.preprocessing 패키지: 스케일링, 변환

missingno 패키지

현실에서 데이터를 수집하다보면 데이터의 일부를 얻지 못하거나 누락되는 결측(missing) 데이터가 생긴다. missingno 패키지는 pandas 데이터프레임에서 결측 데이터를 찾는 기능을 제공한다. 이 패키지를 사용하려면 데이터프레임에 결측 데이터가 NaN(not a number) 값으로 저장되어 있어야 한다.

주의할 점은 NaN값은 부동소수점 실수 자료형에만 있는 값이므로 정수 자료를 데이터프레임에 넣을 때는 Int64Dtype 자료형을 명시해주어야 하고 시간 자료형을 넣을 때도 parse_dates 인수로 날짜시간형 파싱을 해주어야 datetime64[ns] 자료형이 되어 결측 데이터가 NaT(not a time) 값으로 표시된다.

In [1]:
from io import StringIO

csv_data = StringIO("""
x1,x2,x3,x4,x5
1,0.1,"1",2019-01-01,A
2,,,2019-01-02,B
3,,"3",2019-01-03,C
,0.4,"4",2019-01-04,A
5,0.5,"5",2019-01-05,B
,,,2019-01-06,C
7,0.7,"7",,A
8,0.8,"8",2019-01-08,B
9,0.9,,2019-01-09,C
""")

df = pd.read_csv(csv_data, dtype={"x1": pd.Int64Dtype()}, parse_dates=[3])
df
Out:
x1 x2 x3 x4 x5
0 1 0.1 1.0 2019-01-01 A
1 2 NaN NaN 2019-01-02 B
2 3 NaN 3.0 2019-01-03 C
3 NaN 0.4 4.0 2019-01-04 A
4 5 0.5 5.0 2019-01-05 B
5 NaN NaN NaN 2019-01-06 C
6 7 0.7 7.0 NaT A
7 8 0.8 8.0 2019-01-08 B
8 9 0.9 NaN 2019-01-09 C

판다스 데이터프레임 자체도 isnull() 또는 isna() 메서드로 사용하면 결측 데이터의 위치를 알아내는 것이 가능하다.

In [2]:
df.isnull()
Out:
x1 x2 x3 x4 x5
0 False False False False False
1 False True True False False
2 False True False False False
3 True False False False False
4 False False False False False
5 True True True False False
6 False False False True False
7 False False False False False
8 False False True False False

하지만 데이터가 많은 경우에는 일일히 확인할 수 없으므로 기껏해야 sum() 메서드를 결합하여 결측 데이터의 갯수를 유추하는 것만 가능하다.

In [3]:
df.isnull().sum()
Out:
x1    2
x2    3
x3    3
x4    1
x5    0
dtype: int64

하지만 missingno 패키지를 사용하면 대규모의 데이터에서도 결측 데이터에 대한 시각화를 쉽게 할 수 있다. matrix() 함수는 결측 데이터를 시각화하는 명령이다. 결측된 데이터는 흰색으로, 그렇지 않은 데이터는 검은색으로 나타난다. 가장 오른쪽에 있는 것은 스파크라인(spark line)이라고 부르고, 각 행의 데이터 완성도를 표현한다.

In [4]:
import missingno as msno

msno.matrix(df)
plt.show()

만약 각 열에 결측 데이터가 얼마나 존재하는지 시각화 하고 싶다면, bar() 함수를 사용한다.

In [5]:
msno.bar(df)
plt.show()

대규모 데이터에서 missingno 패키지가 어떻게 쓰일 수 있는지 살펴보기 위해 타이나닉 생존자 데이터를 예로 들어본다. 타이타닉 생존자 데이터는 seaborn 패키지에서 제공하는 예제 데이터다.

In [6]:
titanic = sns.load_dataset("titanic")
titanic.tail()
Out:
survived pclass sex age sibsp parch fare embarked class who adult_male deck embark_town alive alone
886 0 2 male 27.0 0 0 13.00 S Second man True NaN Southampton no True
887 1 1 female 19.0 0 0 30.00 S First woman False B Southampton yes True
888 0 3 female NaN 1 2 23.45 S Third woman False NaN Southampton no False
889 1 1 male 26.0 0 0 30.00 C First man True C Cherbourg yes True
890 0 3 male 32.0 0 0 7.75 Q Third man True NaN Queenstown no True

각 열이 의미하는 바는 다음과 같다.

  • survived : 생존 여부
  • pclass : 승객의 클래스
  • sex : 성별. male, female로 표기
  • sibsp : 형제 혹은 자매의 수
  • parch : 부모 혹은 자녀의 수
  • fare : 탑승 요금
  • embarked : 출발지의 고유 이니셜
  • class : 선실의 클래스
  • who : male, female을 man, woman으로 표기
  • adult_male : 성인 남성 인지 아닌지 여부
  • deck : 선실 고유 번호의 가장 앞자리 알파벳(A ~ G)
  • embark_town : 출발지
  • alive : 생존 여부 데이터를 yes 혹은 no로 표기
  • alone : 가족이 없는 경우 True

missingno를 이용하여 타이타닉 데이터를 살펴보면 age, deck, embarkd, embark_town 열 등에 결측 데이터가 있는 것을 볼 수 있다.

In [7]:
msno.matrix(titanic)
plt.show()
In [8]:
msno.bar(titanic)
plt.show()

결측된 데이터를 처리하는 방법은 두 가지다.

  • 결측된 데이터가 너무 많은 경우 해당 데이터 열 전체를 삭제할 수 있다.
  • 결측된 데이터가 일부인 경우 가장 그럴듯한 값으로 대체할 수 있다. 이를 결측 데이터 대체(imputation)라고 한다.

판다스의 dropna() 메서드를 사용하면 결측 데이터가 존재하는 행이나 열을 지울 수 있다. 다음 코드는 위에서 예로 든 df 데이터프레임에서 결측 데이터가 존재하는 모든 행을 지운다.

In [9]:
df.dropna()
Out:
x1 x2 x3 x4 x5
0 1 0.1 1.0 2019-01-01 A
4 5 0.5 5.0 2019-01-05 B
7 8 0.8 8.0 2019-01-08 B

axis 인수를 1로 설정하면 결측 데이터가 있는 열을 제거한다.

In [10]:
df.dropna(axis=1)
Out:
x5
0 A
1 B
2 C
3 A
4 B
5 C
6 A
7 B
8 C

thresh 인수를 사용하면 특정 갯수 이상의 비결측 데이터가 있는 행 또는 열만 남긴다.

In [11]:
df.dropna(thresh=7, axis=1)
Out:
x1 x4 x5
0 1 2019-01-01 A
1 2 2019-01-02 B
2 3 2019-01-03 C
3 NaN 2019-01-04 A
4 5 2019-01-05 B
5 NaN 2019-01-06 C
6 7 NaT A
7 8 2019-01-08 B
8 9 2019-01-09 C

타이타닉 데이터에서 deck 데이터는 결측된 데이터가 너무 많기 때문에 이 방법으로 데이터를 삭제한다.

In [12]:
# 데이터가 절반 이상이 없는 열을 삭제
titanic = titanic.dropna(thresh=int(len(titanic) * 0.5), axis=1)
msno.matrix(titanic)
plt.show()