머신러닝 알고리즘을 위한 데이터 준비

이전 포스팅 '머신러닝을 위한 데이터 가져오기', '머신러닝을 위한 테스트 세트 만들기'에 이어 진행됩니다.

머신러닝 알고리즘을 위해 데이터를 준비할 차례입니다. 이러한 작업들은 아래와 같은 이유로 함수를 통해 자동화됩니다.

  • 어떤 데이터셋에 대해서도 데이터 변환을 쉽게 반복할 수 있습니다.
  • 향후 프로젝트에 사용할 수 있는 변환 라이브러리를 점진적으로 구축하게 됩니다.
  • 실제 시스템에서 알고리즘에 새 데이터를 주입하기 전에 변환시키는 데 이 함수를 이용합니다.
  • 여러 가지 데이터 변환을 쉽게 시도해볼 수 있고 어떤 조합이 가장 좋은지 확인하는 데 편리합니다.

먼저 원래 훈련 세트로 복원하고, 예측 변수와 타깃 값에 같은 변형을 적용하지 않기 위해 예측 변수와 레이블을 분리하도록 하겠습니다.

Code

housing = strat_train_set.drop("median_house_value", axis=1)
housing_labels = strat_train_set["median_house_value"].copy()



1. 데이터 정제

대부분의 머신러닝 알고리즘은 누락된 특성을 다루지 못하므로 이를 처리할 수 있는 함수를 몇 개 만들도록 하겠습니다. 방법은 아래와 같이 세 가지입니다.

  • 해당 구역을 제거합니다.
  • 전체 특성을 삭제합니다.
  • 어떤 값으로 채웁니다. (0, 평균값, 중간값 등)


데이터 프레임의 dropna(), drop(), fillna() 함수를 이용하면 이런 작업들을 간단히 처리할 수 있습니다.

Code

housing.dropna(subset=["total_bedrooms"]) # Option 1
housing.drop("total_bedrooms", axis=1) # Option 2
median = housing["tottal_bedrooms"].median() # Option 3
housing["total_bedrooms"].fillna(median, inplace=True)



하지만, 사이킷런의 Imputer는 누락된 값을 손쉽게 다루도록 해줍니다. 먼저 누락된 값을 특성의 중간값으로 대체한다고 지정하여 Imputer 객체를 생성합니다. 중간값이 수치형 특성에게만 계산될 수 있기 때문에 텍스트 특성인 ocean_proximity를 제외한 데이터 복사본을 생성합니다. 이후 imputer 객체의 fit() 함수를 사용해 훈련 데이터에 적용합니다.

imputer는 각 특성의 중간값을 계산하여 그 결과를 객체의 statistics_ 속성에 저장합니다. total_bedrooms 특성에만 누락된 값이 있지만, 나중에 시스템이 서비스될 때 새로운 데이터에서 어떤 값이 누락될지 확신할 수 없으므로 모든 수치형 특성에 imputer를 적용하는 것이 바람직할 것입니다.

Code

from sklearn.preprocessing import Imputer

imputer = Imputer(strategy="median")
housing_num = housing.drop("ocean_proximity", axis=1)
imputer.fit(housing_num)

print(imputer.statistics_)
print(housing_num.median().values)

Output

imputer 객체에 중간값이 정상적으로 학습된 것을 확인할 수 있습니다.



이제 학습된 imputer 객체를 사용해 훈련 세트에서 누락된 값을 학습한 중간값으로 바꿀 수 있습니다.

Code

X = imputer.transform(housing_num)
housing_tr = pd.DataFrame(X, columns=housing_num.columns,
index=list(housing.index.values))



2. 텍스트와 범주형 특성 다루기

앞서 살펴본 범주형 특성 ocean_proximity가 텍스트라 중간값을 계산할 수 없었습니다.

대부분의 머신러닝 알고리즘은 숫자형을 다루므로 이 카테고리를 텍스트에서 숫자로 바꾸도록 하겠습니다.
이를 위해 각 카테고리를 다른 정숫값으로 매핑해주는 판다스의 factorize() 함수를 사용합니다.

Code

housing_cat = housing["ocean_proximity"]
housing_cat_encoded, housing_categories = housing_cat.factorize()
housing_cat_encoded[:10]

print(housing_cat_encoded)

Output



위와 같은 표현 방식의 문제는 머신러닝 알고리즘이 가까이 있는 두 값이 떨어져 있는 두 값보다 더 비슷하다고 생각한다는 점입니다. 
이 문제는 일반적으로 카테고리별 이진 특성을 만들어 해결합니다. 한 특성만 1이고 나머지는 0이므로 이를 원-핫 인코딩(One-Hot Encoding)이라고 부릅니다.

사이킷런은 숫자로 된 범주형 값을 원-핫 벡터로 바꿔주는 OneHotEncoder를 제공합니다. 카테고리들을 원-핫 벡터로 인코딩 해보겠습니다. fit_transform() 함수는 2차원 배열을 넣어줘야 하는데 housing_cat_encoded는 1차원 배열이므로 구조를 바꿔주어야 합니다. 또한 출력 형태가 사이파이(Scipy) 희소 행렬입니다. 이는 수천 개의 카테고리가 있는 범주형 특성일 경우 매우 효율적입니다. 이런 특성을 원-핫 인코딩하면 열이 수천 개인 행렬로 변하고 각 행은 1이 하나뿐이고 그 외에는 모두 0으로 채워져 있을 것입니다. 0을 모두 메모리에 저장하는 것은 낭비이므로 희소 행렬은 0이 아닌 원소의 위치만 저장합니다. 이 행렬을 거의 일반적인 2차원 배열처럼 사용할 수 있지만 넘파이 배열로 바꾸려면 toarray() 함수를 호출하면 됩니다.

Code

from sklearn.preprocessing import OneHotEncoder
encoder = OneHotEncoder()
housing_cat_1hot = encoder.fit_transform(housing_cat_encoded.reshape(-1,1))
print(housing_cat_1hot.toarray())

Output




References

  • 오렐리앙 제롱, '핸즈온 머신러닝', 한빛미디어, 2018



+ Recent posts