반응형

원본 링크



Preprocessing in Data Science (Part 1): Centering, Scaling, and KNN

이 글은 얼마나 센터링(centering)과 스케일링(scaling)이 모델 성능을 개선할 수 있는지 시험하는 것으로 ML 파이프라인(pipeline)에서 전처리(preprocessing)의 중요성을 설명한다.


데이터 전처리는 데이터 과학자가 하고자 하는 것에 좀 더 적합한 형식으로 데이터를 얻기 위해 사용하는 다양한 작업을 포함하는 포괄적인 용어이다. 예를 들어 트위터 데이터의 감정 분석전에 HTML tag, 공백, 약어 확장을 제거하고 트윗을 단어의 목록으로 분리하고 싶을 것이다. 공간적 데이터 분석시에는 단위 독립적(unit-independent)이도록 축척(scale)을 변경할 것이다. 이것은 알고리즘이 원래 측정이 mile이건 centimeter건 상관하지 않도록 한다. 그러나 데이터를 전처리하는 것은 진공상태에서는 발생하지 않는다. 이것 전처리가 목표를 위한 수단이고 엄격하고 빠른 규칙이 없다는 것을 말한다: 앞으로 알아보게 되겠지만, 표준 관행(standard practices)가 있고 무엇이 동작할지에 대한 직관을 개발할 수 있지만, 최종적으로는 전처리가 결과지향(result-oriented) 파이프라인의 일반적인 부분이고 이것의 성능은 맥락에서 판단되어야 한다.

이글에서는 더 큰 구조의 부분인 ML 파이프라인으로써 전처리를 고려햐는 것의 중요성을 증명하기 위해 수치적 데이터 스케일링의 예를 사용한다. 끝으로 스케일링이 모델 성능을 개선할 수 있는 실제 예제를 살펴본다.

수치적 데이터(numerical data) : 숫자로 구성된 데이터, 반대는 범주적-categorical/문자열-strings

스케일링(scaling) : 데이터의 범위(range)를 바꾸기 위해 수학을 사용하는 것

우선, 이러한 설정에서 사용되는 가장 간단한 알고리즘 중 하나인 ML과 KNN(K-Nearest Neighbors)에서 분류 문제를 살펴본다. 이러한 설정에서 수치적 데이터 스케일링의 중요성을 인식하기 위해 모델 성능의 측정과 훈련과 테스트 셋의 개념을 먼저 알아본다. 레드와인의 품질을 분류하는 데이터셋을 다룰때 이들 개념과 관행을 살펴볼 것이다. 또한, 가장 유용한 장소인 반복적인 데이터 사이언스 파이프라인의 시작점 근처에서 전처리를 한다. 모든 예제는 파이썬을 사용하며, 판다스와 scikit-learn 라이브러를 사용한다.



ML에서의 분류문제

실생활에서 분류(classifying)하고 레이블링(labelling)하는 것은 고대 예술이다. BC.4세기에 아리스토텔레스가 2000년동안 사용된 생물의 분류 시스템을 만들었다. 현대에 분류는 보통 ML 작업, 특히 수퍼바이즈드 러닝 작업(supervised learning task)으로써 분류된다. 수퍼바이즈드 러닝의 기초 이론은 간단하다. 예측 변수(predictor variables)목표 변수(target variables)로 구성된 데이터 묶음이 이다면 수퍼바이즈드 러닝의 목표는 예측변수가 주어지면, 목표 변수를 예측하는 것에 '능숙'한 모델을 구축하는 것이다. 만약 범주('click' 또는 'not', 'malignent' 또는 'benign' 종양)로 구성된 목표 변수라면, 분류(classification) 학습 작업이라고 한다. 만약 목표가 연속적으로 변하는 변수라면, 이는 회귀(regression)작업이다.

나이(age), 성별(sex), 흡연여부(smoker or not)과 같은 75개의 예측 변수와 0(심장병 아님)에서 4까지 범위인 심장병 비율을 나타내느 목표변수로 이루어진 heart disease dataset를 보자. 이 데이터셋의 많은 연구는 심장병의 부재로부터 심장병의 존재를 구분하기 위한 시로데 집중되었다. 이것은 분류 작업이다. 만약 목표 변수의 실제 값(0에서 4)을 예측한다면, (목표 변수가 정렬되어지기 때문에) 회귀 문제가 될 것이다. 횜귀 문제는 다음 글에서 다룰 것이다. 이 글에서는 분류 문제에서 가장 간단한 알고리즘 중 하나인 KNN (K-Nearest Neighbors) 알고리즘을 살펴본다.

 

k-Nearest Neighbors for classification in machine learning

목표 변수로 품질(quality)이고 'good'&'bad'로 레이블링된 레드와인의 특성(알콜 함유, 밀도, 구연산 양, pH등 - 예측 변수)으로 구성된 데이터가 있다고 해보자. 레이블이 되지 않은 새로운 와인의 특성이 주어지면 분류작업은 '품질'을 예측하는 것이 된다. 모둔 예측 변수가 숫자(범주의 경우에도 다룰 수 있는 방법이 있다.)인 경우, n-차원 공간에서 점으로써 각 열/와인을 생각할 수 있다. 이런 경우, KNN이 개적적으로 그리고 계산적으로 간단한 분류 방법이다. 레이블링되지 않은 각각의 새로운 와인에 대해 n-차원 예측 변수 공간에서 이것의 k-최인접 이웃을 계산한다. 그리고
이 k 이웃('good' 또는 'bad')의 레이블을 보고 새로운 와인에 가장 많은 히트를 가진 레이블을 할당한다.(만약 k=3이고 'good'이 3, 'bad'가 2이면 모델은 새로운 와인을 'good'으로 레이블링 한다.) 여기서 모델을 훈련하는 것은 전체적으로 데이터 포인트를 저장하는 것에 있고 학습하기 위한 파리미터가 없다는 것을 기억하자.

 

KNN의 시각적 설명

아래 이미지는 2차원에서의 KNN 예제이다. 중앙에 있는 데이터 포인트를 어떻게 구분할까?
만약 k=3이면 빵강으로 구분할 것이고 k=5이면 파랑으로 구분할 것이다.


 

파이썬으로 KNN 구현(scikit-learn)

이제 KNN 예제를 보자. 이를 위해서 wine quality dataset을 확인하자. 이 데이터를 판다스 데이터프레임으로 임포트하고 예측 변수를 히스토그램으로 그려본다.


import pandas as pd
%matplotlib inline
import matplotlib.pyplot as plt
plt.style.use('ggplot')
df = pd.read_csv('http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv ' , sep = ';')
X = df.drop('quality' , 1).values # drop target variable
y1 = df['quality'].values
pd.DataFrame.hist(df, figsize = [15,15]);

우선 예측 변수의 범위를 보자

  • '유리 이산화황(free sulfur dioxide)' : 0 ~ 70
  • '휘발성 산도(volatile acidity)' : 0 ~ 1.2
    좀 더 구체적으로 유리 이산화황이 휘발성 산도보다 2자리 더 큰 범위를 갖는다. KNN같은 데이터 포인트간 거리를 고려하는 알고리즘은 우리가 아는 한 단지 잡음(noise)만을 포함하는 유리 이산화황 같은 더 큰 범위를 갖는 변수에서 정확하고 불공평하게 초점을 맞출 수 있다. 이것은 데이터 스케일링에 동기를 부여한다.

이제 목표 변수는 3에서 8까지 범위를 갖는 와인의 '품질' 등급이다. 설명의 용이성을 위해 품질을 (등급 > 5)'good'과 (등급 <= 5)'bad'로 구성된 범주 변수로 바꾼다. 또한 어떻게 되고 있는지 알고 위해 목표 변수의 두 공식에 대한 히스토그램을 그린다.


y = y1 <= 5 # is the rating <= 5?
# plot histograms of original target variable
# and aggregated target variable
plt.figure(figsize=(20,5));
plt.subplot(1, 2, 1 );
plt.hist(y1);
plt.xlabel('original target value')
plt.ylabel('count')
plt.subplot(1, 2, 2);
plt.hist(y)
plt.xlabel('aggregated target value')
plt.show()

이제 KNN을 수행하기 위한 준비가 거의 되었다. 모델이 전처리를했을 때와 사용하지 않았을 때의 성능을 비교하려면 모델의 '우수함'을 측정하는 방법을 알아야 한다.

 

k-Nearest Neighbors: how well does it perform?

분류문제를 위한 성능 측정은 여러가지가 있다. 성능 측정의 선택은 특정 도메인&질문에 따라 다르다는 것을 알아차리는 것이 가장 중요하다. 균형 잡힌 클래스를 가진 데이터셋(모든 목표변수가 동일하게 나타나는)의 경우 데이터 과학자는 보통 성능 측정으로 정확도(accuracy)를 본다. 사실 정확도는 scikit-learn에서 KNN과 로지스틱 회귀 모두에 대한 기본 채점 방법이다. 그러면 정확도란 무엇일까? 정확도는 단지 전체 예측수로 올바른 예측 수를 나눈 것이다.

$Accuracy = \frac{Number_of_Correct_Predictions}{Total_Number_of_Predictions}$

Note : accuracy는 또한 혼잡 매트릭스(confusion matrix)로 정의될 수 있고 이는 보통 true positive와 false negative로 이진 분류에 대해 정의된다. 혼자 매트릭스로부터 모델 성능에 대한 다른 일반적인 측정은 정밀도(precision), 재현률(recall), F1-score이다.

 

k-Nearest Neighbors: performance in practice and the train test split

정확도같은 성능 측정을 하는 것은 좋지만 가지고 있는 모든 데이터에서 모델을 학습한다면 어떤 데이터셋에서 정확도를 측정해야 할까? 새로운 데이터에서 잘 일반화되는 모델이 필요하다는 것을 기억하자. 따라서 데어터셋 D에서 모델을 훈련한다면 동일한 데이터 D에서 모델의 정확도를 측정하는 것은 실제보다 더 좋은 성능인 것처럼 보일 것이다. 이것이 오버피팅(overfitting)이다. 이러한 문제에 대응하기 위해 데이터 과학자는 보통 모델을 훈련셋(training set)이라고 불리는 서브셋(subset)에서 훈련하고 훈련셋 이회의 나머지 데이터인 테스트셋(test set)에서 평가한다. 이것이 정확하게 여기서 해야하는 것이다. 일반적인 경험은 데이터의 80%를 훈련셋으로 나머지 20%를 테스트셋으로 사용하는 것이다.

레드와인 데이터셋을 나눠보자.


from sklearn.cross_validation import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

이제 KNN 모델을 구축하자. 테스트셋에서 예측을 수행하고 모델 성능 측정을 위해 이 예측을 실측(ground truth)과 비교한다.


from sklearn import neighbors, linear_model

knn = neighbors.KNeighborsClassifier(n_neighbors = 5)
knn_model_1 = knn.fit(X_train, y_train)
print('k-NN accuracy for test set: %f' % knn_model_1.score(X_test, y_test))

k-NN accuracy for test set: 0.612500

scikit-learn에서 기본 채점 방법이 정확도라는 것을 반복할 가치가 있다. 61%의 정확도는 크지않지만 어떠한 전처리 없이 즉시 사용가능한 모델에 대해 끔직한 결과는 아니다. 다양한 다른 지표(metircs)로 점검해보기 위해 scikit-learn의 classification report 또한 사용할 수 있다.


from sklearn.metrics import classification_report

y_true, y_pred = y_test, knn_model_1.predict(X_test)
print(classification_report(y_true, y_pred))

             precision    recall  f1-score   support

      False       0.66      0.64      0.65       179
       True       0.56      0.57      0.57       141

avg / total       0.61      0.61      0.61       320

이제 스케일링(scaling), 센터링(centering), 수치 데이터의 가장 기본적인 전처리 방법 그리고 이것이 모델 성능에 미치는 영향을 알아보자.



The mechanics of preprocessing: scaling and centering

데이터에서 회귀(연속 변수를 추론하는 것) 또는 분류(구분된 변수를 추론하는 것)같은 모델을 실행하기 전에 대부분 전처리를 한다. 수치 변수의 경우 데이터를 정규화(normalize) 또는 표준화(standardize)를 보통 수행한다. 정규화와 표준화의 뜻은 무엇일까?

  • 정규화(normalization) : 최소값이 0, 최대값이 1이도록 데이터셋을 스케일링하는 것.

    각 데이터 포인트 x를 아래 수식으로 변환한다.

  • $x_{normalized} = \frac{x - x_min}{x_max - x_min}$
  • 표준화(standardization) :데이터를 0 주변으로 분포하게 하고(centering) 표준편차(standard deviation)으로 스케일링

    $\mu$ : 평균
    $\sigma$ : 표준편차

  • 이 변환은 데이터의 범위가 약간 바뀌지만 분포가 바뀌지는 않는다.
  • $x_{standardized} = \frac{x - \mu}{\sigma}$

이후에는 아마도 데이터를 좀 더 정규분포(Gaussian, like a bell-curve)에 가깝게 로그 변환 또는 Box_Cox 변환 같은 다른 몇가지 변환을 사용할 수도 있다. 하지만, 더 진행하기 전에 다음의 의문을 갖는 것이 중요하디.

  • 왜 데이터를 스케일링 하는가?
  • 회귀보다 분류문제가 더 중요한 것 같이 다른 것보다 더 적절한 때가 있는가?

우선 분류 문제를 보고 스케일링이 KNN의 성능에 얼마나 영향을 미치는지 보자.

 

Preprocessing: scaling in practice

아래에서는 전달된 배열(array)에서 모든 특성(feature/columns)을 표준화하는 skikit-learn의 scale function을 사용하여

  1. 데이터 스케일링
  2. KNN 사용
  3. 모델 성능 측정

을 한다.


from sklearn.preprocessing import scale
from sklearn.cross_validation import train_test_split

Xs = scale(X)

Xs_train, Xs_test, y_train, y_test = train_test_split(Xs, y, test_size=0.2, random_state=42)
knn_model_2 = knn.fit(Xs_train, y_train)
y_true, y_pred = y_test, knn_model_2.predict(Xs_test)

print('k-NN score for test set: %f' % knn_model_2.score(Xs_test, y_test))
print('k-NN score for training set: %f' % knn_model_2.score(Xs_train, y_train))
print(classification_report(y_true, y_pred))

k-NN score for test set: 0.712500
k-NN score for training set: 0.814699
             precision    recall  f1-score   support

      False       0.72      0.79      0.75       179
       True       0.70      0.62      0.65       141

avg / total       0.71      0.71      0.71       320

모든 측정치가 0.1 개선되었다. 위의 힌트처럼 스케일링 전에 다른 단위의 범위를 가진 예측변수와 하나 또는 두개가 KNN같은 알고지즘의 맥락에 영향을 끼칠수 있는 평균이 있다. 이것이 데이터를 스케일링하는 두가지 주요 이유이다.

  1. 예측변수 크게 다른 범위일 수 있고 KNN을 구현할때 같은 특정 상황에서 이것은 어떤 특성이 알고리즘에 큰 영향을 끼치지 않게 하기 위해 완화되어야 한다.
  2. 특성이 단위 독립적(unit-independent), 즉 관련된 측정의 규모(scale)에 관련되지 않아야 한다. 예를 들면, 미터로 표현된 측정 특성이 있고 센치미터로 표현된 동일한 특성이 있다고 하자. 만약 각 데이터를 스케일링 한다면, 이 특성은 각각에 대해 동일하게 될 것이다.

스케일링과 센터링 형식에서 전처리로 데이터 과학적 파이프라인에서 차지하고 있는 필수적인 영역을 보았다. 그리고 ML의 문제에 전체적인 접근을 촉진하기 위해 사용했다. 이후 글에서는 수치 데이터의 변환(transformation)과 범주 데이터의 전처리 같은 전처리의 다른 형태로 확대하고 싶다. 두가지 모두 데이터 과학자의 필수적인 측면이다.(관련 필자의 글을 찾지 못했다.) 다음 글에서는 분류로의 회귀 접근에서 스케일링의 역할을 살펴본다. 특히, 로지스틱 회귀를 살펴보고 KNN의 맥락에서 본것과 매우 다른 결과를 보게 된다.

아래 코드로 실행 해 볼 수 있다. KNN알고리즘에서 사용하기 위한 이웃의 수인 n_neig 변수를 바꿔서 시작할 수 있다. 또한 sc=True로 설정하여 데이터를 스케일링할 수 도 있다. 실행하면 분류결과와 함께 모델의 정확도를 보여준다.


# Set the the number of neighbors for k-NN 
n_neig = 5 

# Set sc = True if you want to scale your features 
sc = False 

# Load data 
df = pd.read_csv('http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv ' , sep = ';') 
X = df.drop('quality' , 1).values 

# drop target variable 
# Here we scale, if desired 
if sc == True: X = scale(X) 

# Target value
y1 = df['quality'].values 

# original target variable 
y = y1 <= 5 

# new target variable: is the rating <= 5? 
# Split the data into a test set and a training set 
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) 

# Train k-NN model and print performance on the test set 
knn = neighbors.KNeighborsClassifier(n_neighbors = n_neig) 
knn_model = knn.fit(X_train, y_train) 
y_true, y_pred = y_test, knn_model.predict(X_test)

print('k-NN accuracy for test set: %f' % knn_model.score(X_test, y_test)) 
print(classification_report(y_true, y_pred)) 

 

Supervised learning : 예측 변수(predictor variable)에서 목표 변수(target varable)을 추론하는 작업. 예를 들면, 나이, 성별, 흡연여부 같은 예측변수로부터 '심장병 존재'인 목표변수를 추론하는 것.

분류 작업 - Classification task : 만약 목표변수가 범주( 'click' or 'not', 'malignant' or 'benign' tumour)로 구성되어 있다면, Supervised learning 작업은 분류작업이다.

회귀 작업 - Regression task : 만약 목표 변수가 연속적인 다양한 값(주택 가격 같은)이거나 와인의 품질 등급 같은 순서가 있는 범주 변수라면 Supervised learning 작업은 회귀작업이다.

k-Nearest Neighbors : 분류작업을 위한 알고리즘으로 k 근접 이웃의 가장 많은 수 투표로 결정된 레이블을 데이터 포인터에 할당한다.

Preprocessing : 데이터 과학자가 원하는 좀 더 적합한 형태로 데이터를 얻기 위해 사용하는 연산들. 예를 들면, 트위터 데이터의 감정 분석을 수행하기 전에 html 태그, 공백, 확장 축약어를 제거하고 문장을 단어 목록으로 분할하는 것.

Centering and Scaling :

  • centering : 변수의 평균이 0이 되도록 각 데이터 포인트에서 평균을 빼는 것이다.
  • scaling : 데이터의 범위를 바꾸기 위해 각 데이터의 포인터에 상수를 곱하는 것이다.
반응형

+ Recent posts