티스토리 뷰

* 참고 번역 사이트

http://blog.kaggle.com/2016/07/21/approaching-almost-any-machine-learning-problem-abhishek-thakur/


(거의) 모든 기계학습 문제에 접근하기 | Abhishek Thakur

 

  데이터과학자들은 매일 많은 데이터를 다룬다. 몇몇은 60-70%의 시간을 데이터 처리, munging 그리고 적절한 형태로 데이터를 옮기는 데 써서 기계학습 모델이 그러한 데이터에 적용될 수 있게끔 만든다. 이번 포스트에서는 전처리 스텝을 포함하여 두 번째 파트, 예를 들어 기계학습을 적용시키는 부분에 초점을 맞춘다. 이번 포스트에서 논의되는 연결통로는 내가 참가한 수백 번의 기계학습 대회에서 나온 결과물이다. 이는 매우 일반적이지만 유용하며 또한 전문가들이 실제로 쓰고 존재하는 매우 복잡한 방법일 수 있다는 것을 알아야 한다.

 

우리는 파이썬을 쓸 것이다.

 

<데이터>

  기계학습 모델을 적용하기 전에, 데이터는 표 형식(tabular)으로 변환해야 한다. 이러한 프로세스 전체에서 가장 시간을 소비하고 어려운 과정이며 밑의 그림에서 묘사되어 있다.

 


  그리고 나서 기계학습 모델들은 이러한 표 형식(tabular) 데이터에서 적용된다. 표 형식의(tabular) 데이터는 기계학습 및 데이터 마이닝에서 데이터를 나타내는 가장 일반적인 방식이다. 우리는 데이터 테이블, 다양한 표본들로 이뤄진 데이터(또는 X)를 가진 행들과 라벨(또는 Y)을 가지고 있다. 이러한 라벨들은 문제 형태에 따라 단일 컬럼 또는 복수의 컬럼일 수 있다. 여기서 우리는 Xdata, Y를 라벨로 나타낼 것이다.

 

<라벨 형식>

  라벨들은 문제를 정의하고 다음과 같이 다양한 형식일 수 있다.

* 단일 컬럼, 이진 값(분류(classification) 문제, 하나의 표본이 딱 두 개의 등급(class) 가운데 하나의 등급(class)만을 가지고 있음)

* 단일 컬럼, 실제 값(회귀 문제, 오직 하나의 값에 대한 예측)

* 복수 컬럼, 이진 값(분류 문제, 하나의 표본에는 하나의 등급에 속해있지만 등급은 2개보다 많이 이뤄져 있다.)

* 복수 컬럼, 실제 값(회귀 문제, 여러 값들에 대한 예측)

* 복수 라벨(분류 문제, 하나의 표본이 여러 등급에 속할 수 있다)

 

<라이브러리>

  기계학습 라이브러리를 시작하기 위해, 기본적이고 가장 중요한 것들을 먼저 설치하자(예를 들면 numpyscipy).

 

* 데이터를 보고 데이터 상에서 작업을 하기 위해

  : pandas (http://pandas.pydata.org/)

* 모든 종류의 기계 학습 모델을 위해

  : scikit_learn (http://scikit-learn.org/stable/)

* 최고의 gradient boosting 라이브러리

  : xgboost (https://github.com/dmlc/xgboost)

* 신경망 네트워크를 위해

  : keras (http://keras.io/)

* 데이터를 그래프로 나타내기 위해

  : matplotlib (http://matplotlib.org/)

* 과정을 모니터하기 위해

  : tqdm (https://pypi.python.org/pypi/tqdm)

 

  나는 아나콘다(https://www.continuum.io/downloads)를 사용하지 않는다. (아나콘다는) 쉽고 모든 것을 할 수 있지만 나는 더 많은 자유를 원한다. 물론 선택은 당신의 몫이다.

 

<기계 학습 구조>

 2015년에 여전히 발전 중이고 앞으로 나타날 자동 기계학습을 위한 구조를 생각해냈다. 이번 포스트를 위해 다음과 같은 구조가 기초가 될 것이다. 구조는 밑의 그림에 나와 있다.

  위에 보여진 그림에서 분홍색 선은 가장 공통적인 길을 나타낸다. 우리는 표 형식(tabular) 형식으로 데이터를 추출하고 줄인 이후에, 기계학습 모델을 도입할 수 있다.


  가장 첫 번째 단계는 문제 인지(identification)이다. 이는 라벨을 보는 것으로 이뤄질 수 있다. 만약 문제가 이진 분류(classification)인지, 복수 계층(class) 또는 복수 라벨 혹은 회귀 문제인지 알아야한다. 그렇게 문제가 무엇인지 알고 난 후, 데이터는 (밑에 묘사된) 훈련용(training), 검증용(validation) 두 가지 부분으로 분리한다.

 


  훈련용과 검증용으로 쪼개는 것은 반드시 라벨에 따라 이뤄져야 한다. 어떠한 종류의 분류 문제에서 층화 추출(stratified splitting)을 사용하라. 파이썬에서는 scikit-learn으로 쉽게 사용할 수 있다.

 


  회귀 문제에서는 간단히 k겹 추출(K-Fold splitting)이면 충분하다. 그러나 라벨 분배를 훈련용·검증용 데이터에 똑같이 유지하려 하는 몇몇 복잡한 방법들이 있는데 이는 독자의 실습으로 남겨둔다.

 

  나는 eval_size 또는 전체 데이터의 10%만큼의 검증용 데이터 양을 선택해왔지만, 어떤 사람은 그들이 갖고 있는 데이터 양에 따라 선택할 수 있다.

 

  데이터를 쪼개(분리)는 것이 이뤄지고 나면, 데이터를 내버려두고, 건드리지 마라. 훈련용 데이터에 적용된 어떠한 작업들도 저장되고, 검증용 데이터가 되어야 한다. 어떤 케이스에서도 검증용 데이터는 훈련용 데이터에 들어가면 안된다. 그렇게 되면, 평가 점수가 매우 좋아서 행복한 기분이 들 수 있지만, 대신에 과적합(high overfitting)으로 쓸모없는 모델을 세우게 될 것이다.

 

  다음 단계는 데이터에서 다양한 변수를 인지하는 것이다. 우리가 다룰 수 있는 세 가지 형태가 있다. 다시 말해, 수치형(numerical) 변수, 명목형(categorical) 변수, 그것들 안에 문자(text)가 들어있는 변수이다. 인기 있는 타이타닉(Titanic) 데이터의 예시를 들어 보자(https://www.kaggle.com/c/titanic/data).

 


  여기, 생존(survival)이 라벨이다. 우리는 이미 이전 단계에서 훈련용 데이터로부터 라벨을 분리했다. 그리고 승객 등급(pclass), 성별(sex), 승선(embarked)를 갖고 있다. 이러한 변수들은 다른 레벨을 가지고 있고, 명목 변수이다. 성별(age), 형제자매/배우자의 수(sibsp), 부모/자녀의 수(parch) 등들은 수치형 변수이다. 이름(Name)은 문자형 변수이지만 나는 생존을 예측하는데 유용한 변수라고 생각하지 않는다.

 

  수치형 변수를 우선 분리시켜보자. 이러한 변수들은 전처리(processing)하는데 어떠한 것도 필요하지 않기에 이러한 변수들에 정규화(normalization)와 기계학습 모델을 적용 시작할 수 있다.

 

  명목형 데이터를 다루는 데 두가지 방법이 있다.

1. 명목형 데이터를 라벨로 전환시키기

 

2. 라벨을 이진형 변수로 전환시키기(one-hot encoding)


  여기서 기억해 놓아야 할 것은 명목형(categories)을 수치형(numbers)으로 전환시킬 때 OneHotEncoder를 적용하기 전에 LabelEncoder를 먼저 사용하는 것이다.

 

  왜냐하면, 타이타익 데이터는 문자형 변수에 좋은 사례가 아니기 때문이다. 문자형 변수를 다루는 데 일반적인 법칙을 만들어 보자. 모든 문자형 변수를 하나로 섞을 수 있고, 문자형 데이터를 가지고 수치형으로 전환시킬 수 있는 몇몇 알고리즘을 사용할 수 있다.

 

  문자형 변수를 다음에 따라 해보자.


  우리는 CountVectorizer 또는 TfidfVectorizer를 여기에 쓸 수 있다.


  또는,


  TfdifVectorizer는 시간의 대부분을 세는 것보다(?) 훨씬 더 좋게 수행하며 나는 다음의 TfidfVectorizer 파라미터들이 거의 모든 시간에 작동하는 것을 봐왔다.

 

  만약 당신이 훈련용 데이터에서만 이러한 vectorizer를 적용하고 있다면, 확실히 하드 드라이브에 버려라(?). 그리고 나면, 후에 검증용 데이터에 쓸 수 있다.

 

  다음으로, Stacker Module(스태커 모듈)이다. Stacker Module(스태커 모듈)model stacker(모델 스태커)가 아닌 feature stacker(특징 스태커)이다. 전처리 이후 다양한 특징들은 밑에 그려진 대로 stacker module에 사용하는 데 결합할 수 있다.


  당신은 numpy hstack 또는 sparse hstack을 가지고 보다 더 전처리를 통해서 그것들을 쌓아놓기 전에 당신이 dense 또는 sparse한 특성들을 가지고 있느냐 없느냐에 따라 수평적으로 모든 특성들을 쌓을 수 있다.


  또한 pca 또는 특성 선택(feature selection) 같은 다른 전처리 단계가 있는 경우에서는 FeatureUnion module을 가지고 얻어질 수 있다(우리는 이번 포스트 이후에 분해(decomposition) 그리고 특성 선택을 볼 것이다).


   우리가 특성(feature)들을 갖고 쌓을 때, 기계 학습 모델 적용을 시작할 수 있다. 이번 단계에서 해야 할 것은 모델 기반의 앙상블 나무 모델(ensemble tree based model)을 해야 한다. 이러한 모델에서는 다음을 포함한다.

 

* RandomForestClassifier

* RandomForestRegressor

* ExtraTreesClassifier

* ExtraTreesRegressor

* XGBClassifier

* XGBRegressor

 

  우리는 선형모델을 위의 특성에다 적용시킬 수 없다. 왜냐하면 그것들은 정규화되지 않았기 때문이다. 선형 모델로 쓰기위해서는 scikit-learn에서 Normalizer 또는 StandardScaler를 쓸 수 있다.

 

  이러한 정규화 방법들은 dense(복잡한, 난해한) feature(특성)에서 작업하는데 만약 sparse feature에서 적용하려면 좋은 결과를 내지 못한다. 맞다, sparse matrices에서는 평균(parameter: with_mean=False)을 사용하지 않고 StandardScaler를 적용할 수 있다.

 

  만약 위의 단계에서 좋은모델을 준다면, 우리는 hyperparameter의 최적화에 해당할 수 있는데, 이는 다음의 단계에 해당하지 않고, 우리의 모델을 개선하지 못할 수 있다.

 * hyperparameter : (label, en, statistics) In Bayesian statistics, a parameter of a prior (as distinguished from parameters of the model for the underlying system under analysis).

 

  다음의 단계는 분해(decomposition) 방법을 포함한다.



  단순함을 위해, 우리는 LDAQDA 전환을 빼버릴 것이다. 높은 차원의 데이터를 위해서 일반적으로 PCA는 데이터를 분해하는데 사용된다. 10-15 성분의 이미지를 갖고 시작하고 이 숫자를 결과의 품질을 지속적으로 개선시키는 한 늘려간다. 다른 형태의 데이터를 위해 우리는 초기에 50-60 성분을 선택한다(우리가 수치형 데이터를 다룰 수 있는 한 가능한 한 PCA를 피하려고 한다).



  문자형 데이터를 위해서는, 문자를 sparse matrix로 전환한 이후에, Singular Value Decomposition(SVD)을 한다. TruncatedSVD라 불리는 SVD의 변화(variation)는 scikit-learn에서 볼 수 있다.

 

  일반적으로 TF-IDF를 위해 작업하는 SVD 성분의 숫자는 120에서 200 사이이다. 이를 넘는 어떠한 숫자라도 성과를 개선할 수 있지만, 지속적이지 않고 계산력을 희생을 바탕으로 한다.

 

  모델 성과를 평가하기 위해 우리는 데이터셋의 규모(scaling of the dataset)로 가야 선형 모델도 평가할 수 있다. 정규화된 또는 스케일된 특성(scaled feature)들은 기계학습 모델 또는 특성 선택 모듈로 보내질 수 있다.



  특성 선택(feature selection)에는 여러 가지 방법이 있는데 가장 많이 쓰는 방법 중의 하나는 greedy feature selection(forward 또는 backward)이 있다. greedy feature selection에서는 하나의 특성을 선택하고 모델을 가지고 훈련(train)하며, 고정된 평가 metric에서 모델 성과를 평가한다. 우리는 지속적으로 하나씩 특성을 추가하고 제거하고, 모든 단계에서 모델 성과를 기록한다. 그리고 나서 가장 좋은 평가 점수를 가진 특성을 선택한다. 평가 metric으로서 AUC를 갖고 한 greedy feature selection 실행은 여기서 볼 수 있다.

https://github.com/abhishekkrthakur/greedyFeatureSelection

  여기서의 실행이 완벽한 것은 아니고 요구에 따라 변화/수정되어야 한다.

 

  feature selection의 또 다른 빠른 방법은 모델에서 최고의 특성을 선택하는 걸 포함한다. 우리는 로짓(logit)모델의 계수를 볼 수 있을 뿐만 아니라 랜덤포레스트를 훈련시켜 최고의 특성(feature)를 선택하고 그것들을 다른 기계학습 모델과 함께 사용할 수 있다.



  적은 수의 평가자(estimator)를 유지하고 hyperparameter의 최소한의 최적화(오차가 최소)를 유지하여 과적합되지 않도록 기억하라.

 

  특성 선택(feature selection)Gradient Boosting Machine를 활용해서 얻을 수도 있다. 만약 우리가 scikit-learn에서 GBM의 실행 대신에 xgboost를 사용한다면 좋다. 왜냐하면 xgboost는 더 빠르고 더 확장가능하기 때문이다.



  또한 RandomForestClassifier / RandomForestRegressor 그리고 xgboost를 사용하여 sparse 데이터셋의 특성 선택을 할 수도 있다.

 

  positive sparse 데이터셋에서 feature selection을 하는데 인기 있는 다른 방법은 feature selection 기반의 chi-2가 있는데 scikit-learn에서 실행시킬 수 있다.



  여기에, 우리는 chi2SelectKBest와 결합하여 데이터로부터 20가지 특성들을 선택할 수 있다. 이는 우리가 최적화 하고 싶은 hyperparameter가 되어 기계학습 모델의 결과를 개선시킬 수 있다.

 

  덤프하는 것(정보를 다른 곳으로 복사해 가서 저장하는 것)을 잊지 마라. 검증 세트에서 성과를 평가할 필요가 있을 것이다. 다음(또는 중간) 중요한 단계는 모델 선택 + hyperparameter 최적화이다.

 


 

우리는 일반적으로 기계학습 선택 프로세스에서 다음의 알고리즘을 사용한다.

 

* 분류(Classification):

- Random Forest

- GBM

- Logistic Regression

- Naive Bayes

- Support Vector Machines

- k_nearest Neighbors

 

* 회귀(Regression)

- Random Forest

- GBM

- Linear Regression

- Ridge

- Lasso

- SVR

 

  내가 어떠한 파라미터(parameter)들을 최적화시켜야 되는가? 최적의 파라미터들에 가깝게 파라미터를 어떻게 선택할까? 사람들이 대부분의 시간을 갖고 생각해내는 여러 질문들이 있는데, 많은 데이터셋에서 경험 없이 다양한 모델들과 파라미터를 가지고 이러한 질문들에 대답을 얻을 수 없다. 또한 경험이 있는 사람은 그들의 비밀을 공유하려 하지 않는다. 운좋게도, 나는 어느 정도 꽤 경험이 있는데 그런 것들 몇가지를 알려주려 한다.

 

hyperparameter를 쪼개보자, model wise:

  RS* =이 적절한 값을 말할 순 없고, 이러한 hyperparameterRandom Search가 포함된다.

 

  내 의견으로는, 엄격하게 말하자면, 위의 모델들은 다른 어떠한 것들보다 더 나은 결과를 낼 것이며 우리는 다른 어떠한 모델들을 평가할 필요가 없다.

 

  다시 말하자면, 다음의 변환을 기억하라.

 

 

 

  그리고 그것들을 검증 세트에 따로 적용하라.



 

  위의 규칙들과 구조는 내가 다루는 대부분의 데이터셋에서 가장 잘 수행되어 왔다. 물론, 매우 복잡한 일에서는 실패하기도 했다. 완벽한 것은 없으며 우리는 우리가 배우는 것에서 지속적으로 개선시키고 있다. 단순히 기계학습에서는 말이다.

 

어떠한 질문이 있다면 연락하라. abhishek4 [at] gmail [dot] com

댓글