간만에 칼리를 실행하고, 바뀐 것에 대해 업데이트를 위해

apt-get update 결과 아래와 같이 출력되었다.


W: An error occurred during the signature verification. The repository is not update and the previous index files will be used. 

S: Some index files failed to download. They have been ignored, or old ones used instead. 


별거없다. 아래와 같이 입력해주면 된다.  


wget -q -O - https://archive.kali.org/archive-key.asc | apt-key add


위의 사진처럼 해결됨을 확인 할 수 있다. 


문제가 무엇이었을까?

칼리 리눅스 트위터를 보면 아래와 같이 게시되어 있다.



주기적으로 update를 하지 않았을 때, archive-keyring 패키지가 outdated된다. 그렇기 때문에 kali의 repository의 키와 일치하지 않아 발생하는 오류이다. 


그나저나 칼리가 <3 라니.. 낯설다 너...


반응형

 한빛미디어에서 Hands-On Machine Learning with Scikit-Learn and TensorFlow에 대한 출판권을 획득하여 곧 출간 예정이라고 합니다.

따라서 그간 발행했던 글들은 비공개 처리하고자 합니다. [4장 ~ 13장] 

나름 고생해서 쓴 글들이라 아쉬움이 크지만, 다행히 베타리딩 및 추천사에 참여하기로 하였습니다!!

혹시라도 책 내용이나 궁금한 사항에 대해 댓글을 남겨주시면, 최대한 아는 한에서 답변을 드리고자 합니다.

원서로 공부하기 어려웠던 분들은 구입하셔서 보시면 많이 도움 될 것 같습니다!! 

반응형

우분투 17.01버전이 나왔다고는 하나, 왠지모르게 신뢰할 수 없어 16.04.2 버전으로 설치함

설치 후 apt-get update를 하는데 아래와 같은 메시지가 출력됨..


E: Problem executing scripts APT::Update::Post-Invoke-Success 'if /usr/bin/test -w /var/cache/app-info -a -e /usr/bin/appstreamcli; then appstreamcli refresh > /dev/null; fi'

E: Sub-process returned an error code


한줄이면 끝

sudo apt-get remove libappstream3


다시 apt-get update를 하면 정상적으로 동작하는 것을 확인 할 수 있음!

반응형

03_Classification.ipynb

책: O'REILLY의 Hands-On Machine Learning with Scikit-Learn & TensorFlow

URL: http://shop.oreilly.com/product/0636920052289.do

본문에 사용되는 사진들은 모두 위의 책에서 발췌

소스코드: https://github.com/ageron/handson-ml

틀린 내용이 있으면 언제든지 댓글 달아주세요! (오역은 어느정도 이해해주시길)


chapter3. Classification

chap1에서는 가장 일반적은 지도학습은 회귀(regression)와 분류(classification)이라고 언급했다.

chap2에서는 선형 회귀(Linear Regression), 결정 트리(Decision Trees), 랜덤 포레스트(Random Forests) 알고리즘을 이용하여 주택 가격을 예측하는 회귀 문제를 경험했다.

이제 우리는 분류 시스템에 대해 주목하고자 한다.


MNIST

 이번 장에서 우리는 MNIST 데이터를 이용할 것이다. MNIST데이터는 0에서 9까지의 숫자를 70,000장의 수작업으로 작성 된 데이터 셋이다. 각 이미지는 0에서 9까지의 숫자에 대해 라벨링 되어 있다. 이 데이터 셋은 너무나 많이 연구되어 머신러닝의 "hello world"라고도 불리며, 사람들이 새로운 분류 알고리즘을 적용할 때마다 MNIST에서 어떻게 작동되는지를 알고 싶어한다.

Scikit-learn은 인기있는 데이터 셋을 다운로드 할 수 있는 기능을 제공하는데 그 중 하나가 MNIST이다. 


 

 다운로드 받은 Datasets은 일반적으로 사전식(dictionary) 구조와 유사하다.

  • DESCR key: 데이터셋의 설명(description)
  • data key: 인스턴스당 하나의 행과 feature당 하나의 열이 있는 배열
  • target Key: 라벨을 가진 배열

 총 70,000장의 이미지는 784개의 feature를 가지고 있다. 각각의 이미지는 28*28 픽셀을 가지고 있으며, 각각의 feature는 0(white)에서 255(black)까지의 하나의 픽셀로 나타낼 수 있다. 


 설명만으로는 감을 잡기 어려울 것이다. 이를 실제로 28*28 행렬로 변환하여 이미지를 출력해보자.

0에서 69,999까지의 범위 중 랜덤 값으로 하나를 출력하여 이미지를 출력한 결과이다. 실제 타겟의 값이 8이고, 이미지 또한 8이라는 것을 "우리는" 확인 할 수 있다.

 이제 우리는 2장에서 배운 학습용 데이터와 테스트용 데이터를 분리 해야한다. MNIST 데이터 셋은 실제로 학습데이터(첫 번째 데이터에서 60,000까지의 이미지)와 테스트 데이터(나머지 10,000장의 이미지)로 이미 분리되어 있다.

 또한, 학습용 데이터를 섞어보자(shuffle). 몇몇 알고리즘은 인스턴스의 순서에 민감하다. 그렇기 때문에 섞는 작업을 통해 이러한 문제를 해결할 수 있다.


Training a Binary Classifier

 단순한 문제를 풀어보자. 예를 들어 숫자 5를 식별하는 분류기를 만들어보자. 이 분류기는 단순히 5가 맞다, 아니다의 두가지 클래스만을 가지고 있다. 이 분류 작업을 위해 타겟 벡터를 만들어보자.

 이제 학습을 시켜보자. 시작하기 좋은 방법으로 Scikit-learn의 SGDClassifier 클래스를 이용하여, Stochastic Gradient Descent(SGD) 분류기를 이용하여 시작해보자.

 [Stochastic Gradient Descent 방식은 기존의 경사 하강법(Gradient Descent)이 매 번 모든 데이터들에 대해 살펴보고 기울기를 계산하기 때문에 시간이 많이 소요되는 문제가 있었는데, 이를 개선한 것이다. 책에서 해당 내용에 대해 다루는지 아직 파악이 안되었는데, 다루지 않을 경우 별도로 정리하겠음.]

 이 SGD 분류는 매우 큰 데이터 셋을 다루는 데 매우 효율적이다. 아래의 예제는 some_digit을 X[36000]으로 맞춰 놓은 상태

 이 분류기는 특정한 상황에서만 올바르게 판단된다. 이제 우리는 모델의 성능에 대해 평가해보고자 한다.


1. Performance Measures

 분류기를 평가하는 것은 종종 regressor를 평가하는 것보다 훨씬 더 까다로울 수 있다. 그래서 우리는 이 주제에 대해 이번 장에서 많은 부분을 할애하고자 한다. 사용할 수 있는 성능 측정 방법은 상당히 많다.


1) Measuring Accuracy Using Cross-Validation

 모델을 평가하는 좋은 방법으로는 교차 검증(cross-validation)을 이용하는 것이다.

경우에 따라서, Scikit-learn이 제공하는 것보다 교차-검증을 더욱 제어해야 할 수 있다. 

이러한 경우 쉽게 구현할 수 있다.

다음의 코드는 Scikit-learn의 cross_val_score() 함수와 거의 동일한 결과를 보인다.


 이번에는 cross_val_score() 함수를 사용하여, 3개의 fold를 가진 K-fold cross-validation을 이용한 SGDClassifier 모델을 평가해보자. 


 Wow! 95% 이상의 정확도를 보인다? 

흥분하기 전에, "not-5"클래스의 모든 단일 이미지를 분류하는 멍청한(dumb) 분류기를 살펴보자.

 그렇다. 90%의 정확도를 보인다. 5라는 이미지가 대략 10%정도 차지하고 있기 때문에 나오는 간단한 결과이다.


위 예는 분류를 측정하는, 특히 왜곡(skewed)된 데이터를 다룰 때 선호되는 척도가 아닌지에 대해 증명하고 있다.


2) Confusion Matrix

 분류기의 성능을 평가하는 더 좋은 방법은 confusion matrix를 사용하는 것이다. 일반적인 아이디어는 클래스 A의 인스턴스가 클래스 B로 분류되는 수를 계산하는 것이다. 예를 들어, 5라는 이미지를 3으로 혼동하는 횟수를 알기 위해서는, confusion matrix의 5행 3열을 보면 된다. confusion matrix를 계산하기 위해, 처음으로 예측 Set을 구하고, 그 다음 실제 타겟과 비교하면 된다. test set에서 예측을 할 수 있지만, 일단은 그대로 두자. (test set은 학습을 마치고, 나중에 평가할 때 사용하기 위해 아껴두는 것을 잊지말자!) 대신 cross_val_predict() 함수를 사용할 수 있다. 

 cross_val_score() 함수와 마찬가지로, cross_val_predict() 함수는 K-fold cross-validation을 수행한다. 그러나 evaluation scores값을 반환하는 것 대신에 각각의 test fold에서 만들어지는 예측에 대해서 반환하게 된다. 

 이제 confusion_maxtrix() 함수를 이용하여 confusion matrix를 얻어보자. 

  confusion matrix의 각 행은 actual class를 나타내고, 각 열은 predicted class를 나타낸다. 이 행렬의 첫번째 행은 5가 아닌 것(negative class)을 53,800개로 분류하고(true negatives), 나머지 779개는 5로 잘못 분류한 것이다(false positives).

 다음 행은 5인 것(positive class)을 분류하는 것인데, 1,583개가 잘못 분류 되었지만(false negatives), 나머지 3,838개는 정상적으로 분류 되었다(true positives).

 글로 보려니 아무래도 헷갈린다! 그리고 무엇보다 헷갈렸던 것은 알고 있던 confusion matrix는 행이 예측 클래스, 열이 actual 클래스였는데, scikit-learn에서 반대로 출력되어 헷갈렸다..

 나는 매번 헷갈렸지만, 그래도 그나마 외우기 위한 방법으로는 다음과 같은 방법을 이용했다. 다소 유치할 수는..

"예측을 했는데 5가 아니었네. 실제는 뭐지? 아! 5가 아니네! True Negatives = (뒤에서부터) 아닌게 맞구나~"

"예측을 했는데 5네! 실제는 뭐지? 이런..5가 아니었네... False Positives = (뒤에서부터) 예측이 맞은게 아니었구나.."

"예측을 했는데 5가 아니었네. 실제는 뭐지? 아! 5군... False Negatives = (뒤에서부터) 아닌게 아니었구나.."

"예측을 했는데 5네! 실제는 뭐지? 오! 5가 맞았군! True Positives = (뒤에서부터) 맞춘게 맞구나~"


 confusion matrix는 많은 정보를 줄 수 있지만 때로는 더욱 간결한 것을 원할 수 있다. 이 때 사용되는 것으로는 precision(정밀도)과 recall(재현율) 이 있다.

 정밀도란, 맞다고 예측한 것실제로 맞았는지에 대해 확인하는 지표이다.

 재현율이란, 실제 정답의 True얼마나 많은 true를 예측 했는지에 대해 확인하는 지표이다.


3) Precision and Recall

 scikit-learn은 precision과 recall을 포함하여 classifier metrics 를 계산하는 몇개의 함수를 제공한다.

 이제 숫자 5의 검출기는 이전의 높은 정확도를 보이는 것처럼 높게 나오지는 않는다. 이미지가 5일 때, 83%정도 맞다고 주장한다. 더욱이 5의 70%만 탐지하게 된다.

두 분류기준을 비교하는 간단한 방법이 필요할 때, F1 score라고 불리는 (Precision과 recall을 하나의 metric으로 결합)방법을 사용할 수 있는데, 우리가 알고 있는 조화 평균이 해당 방법이다.

F1 score를 계산하기 위해, 간단하게 f1_score() 함수를 호출하면 된다.


그런데 F1 score 값은 항상 우리가 원하는 값만 출력하는 것은 아니다. 상황에 맞게 precision과 recall 중 중점적으로 생각할 수 있을 것이다.

 예를 들어, 어린이에게 안전한 동영상을 볼 수 있도록 분류기를 훈련하는 가정을 생각해보자. 이러한 경우, 많은 좋은 동영상을 나쁘다고 판단할 수 있다(low recall). 하지만, 많은 분류 기준을 사용하는 분류 기준보다는 안전하다고 판단되는 분류 기준을 선호하게 된다(high precision).

 반면에, 감시 이미지에서 좀도둑을 탐지하도록 분류기를 훈련시킨다고 가정해보자. 이 때에는 precision보다는 recall이 높은게 좋다. 잘못된 알람(맞다고 예측했는데 아닌 경우: low precision)이라고 해도 (경비원들은 엄청 고생하시겠지만..) 실제 도둑을 탐지하는 비율이 높게 된다. 

 위의 두 가지 예를 보면 precision과  recall은 반비례적인 것을 확인 할 수 있다. 이를 Precision/recall tradeoff라고 부른다.


4) Precision/Recall Tradeoff

 tradeoff를 이해하기 위해서, SGDClassifier가 어떻게 분류 결정을(classification decisions) 하는지 살펴보자. 각각의 instance에 대해 decision function 기반으로 점수를 계산하고, 만약 score가 임계 값(threshold)보다 높다면 positive class에 할당하고, 그렇지 않다면 negative class에 할당한다. 

위의 그림은 왼쪽으로의 낮은 점수부터 오른쪽의 높은 점수에 이르기까지 몇개의 숫자를 보여준다. 결정 임계값(decision threshold)를 중간 화살표(5사이)로 가정해보자. 오른쪽을 보면 실제 5라는 숫자가 4개라는 것을 확인할 수 있다. 6은 무엇일까?

앞서 얘기한 False Positive가 될 것이다.(예측은 5였는데 실제값은 5가 아니었군!) 따라서 해당 임계 값을 사용하면 precision은 80%가 될 것이다. TP/(FP+TP) -> 4/(1+4). 그러나 실제 5의 개수는 6개인데 해당 임계 값의 범위에는 5가 4개밖에 포함되어 있지 않다. 그렇기 때문에 recall은 67%가 된다. TP/(TP+FN) -> 4/(4+2)

 이제 임계값을 오른쪽 화살표로 움직여보자. 이 때 precision은 100%가 된다.  TP/(FP+TP) -> 3/(0+3). 그러나 recall은 50%로 감소하게 된다. 3/(3+3). 즉 precision은 높아졌지만, recall은 감소한 것을 확인할 수 있다. 왼쪽으로 화살표를 가면 반대라는 것 또한 확인할 수 있다.

 scikit-learn은 임계값을 직접 설정할 수는 없지만, 예측을 하기 위해 사용하는 의사결정점수(decision score)에 대한 접근을 제공한다. 분류기(classifier)의 predict() 함수를 호출하는 것 대신에, 각각의 인스턴스의 점수를 반환하는 decision_function() 함수를 호출하여 원하는 임계 값을 사용하여 해당 점수를 기반으로 에측을 수행할 수 있다. 

 SGDClassifier는 threshold를 0으로 사용하기 때문에 이전 predict() 함수를 사용했던 결과와 동일하게 True 값을 반환한다. 

이제 임계값을 올려보자. 200,000으로 값을 줄 것이다.

 당연히 y_score 값이 74632었기 때문에 false가 반환된다. 이것이 중요한게 아니라, 임계 값을 높이면 recall이 감소한다는 것이다. 이미지는 실제로 5를 나타내며 분류기는 임계 값이 0일때 5가 맞다는 것을 감지하지만 임계값이 200,000으로 증가하면 탐지 하지 못하게 된다. 그러면 임계값을 어떻게 결정할 수 있을까? 이를 위해서 우리는 cross_val_predict() 함수를 다시 사용하여 training set의 모든 인스턴스 점수를 얻을 것이고, 이번에는 예측하는 것 대신에 의사 결정 점수를 반환하도록 지정할 것이다.

(예측에는 false, true 형식으로 반환되지만, 결정 점수는 값으로 반환된다ㅋ)

 이제 이 점수로, precision_recall_curve() 함수를 사용하여 가능한 모든 임계값에 대해 precision과 recall을 계산할 수 있다.

 한가지 주의해야할 점은 sklearn의 0.19버전의 경우 cross_val_predict함수의 method로 decision_function의 반환 shape는 (60000,2)다. y_train의 경우 (60000,1)이기 때문에 형식이 맞지 않는다며 오류값이 나온다. 그렇기 때문에 위에서 y_scores[:,1]로 했다는 점에 대해 유의 필요.

 위의 그래프에서 precision이 recall보다 왜 왜곡되었는지 궁금해 할 수 있다. (recall 커브가 부드럽게 보인다. )

이유는 임계 값을 올릴 때 정확도가 떨어질 수 있기 때문이다.  위의 precision/recall tradeoff 그림을 보면 설명이 되는데, 중간 화살표인 임계값을 보자. 임계값에서 한 자리수만큼 오른쪽으로 이동시켜보자. 정밀도는 4/5(80%)에서 3/4(75%)라는 것을 확인 할 수 있다. 반면에 recall은 임계 값이 증가 할 때만 값이 내려가는 것을 확인할 수 있다. 그렇기 때문에 커브가 부드럽게 보이는지 설명할 수 있다. 

 위의 방법으로 최적의 precision/recall tradeoff 값을 제공하는 임계값을 간단하게 선택할 수 있게 되었다.  

또 다른 방법으로는 recall에 대한 precision을 직접 plotting 하는 것이다.

 위의 그래프를 보면 precision은 80%가량에서 급격히 떨어지는 것을 확인할 수 있다. 


이제 90%의 precision을 목표로 한다고 가정해보자. threshold를 통한 precision/recall 그래프를 다시 보자. (위의 위의 그래프)

만족하는 threshold는 약 70,000 정도로 보인다. 

70,000을 기준으로 threshold에 값을 준 결과, precision은 90%인 것을 확인 할 수 있다. 참 쉽죠잉~


5) The ROC Curve (Receiver Operating Characteristic)

 ROC Curve는 precision/recall curve와 매우 유사하지만, recall에 대한 precision을 plotting 하는 것 대신, False Positive Rate(FPR)에 대해 True Positive Rate(TPR; recall)을 plotting 하는 것이다. 

 설명이 어려웠다. 그냥 precision/recall은 precision과 recall이 반비례 관계이고, ROC의 경우 TPR과 FPR이 반비례다.

이것을 설명하기 위해서는 민감도(sensitivity)와 특이도(specificity)에 대해 알아야 된다.

1. 민감도(sensitivity): 1인 케이스에 대해 1이라고 예측

2. 특이도(specificity): 0인 케이스에 대해 0이라고 예측

True Positive Rate(TPR)는 민감도와 같다. recall과 같다. (ex: 스팸 메일을 스팸메일이라고 판단함)

False Positive Rate(FPR)는 (1-특이도)와 같다. 즉 0인 케이스에 대해 1로 잘못 예측한 비율이다.
(ex: 스팸 메일이 아닌데 스팸 메일이라고 잘못 판단함)

True Negative Rate(TNR)은 특이도와 같다. (ex:스팸 메일이 아닌 것에 대해 정확하게 판단함)

즉 FPR은 (1-TNR)이다.


 ROC curve를 plot하기 위해, 우선 roc_curve()함수를 이용하여, 다양한 임계값을 통해 TPR과 FPR을 계산하여야 한다.

 recall(TPR)이 높을 수록 분류기가 생성하는 오탐(FPR)이 높아진다. 점선은 purely random classifier를 나타낸다. 좋은 분류기 일수록, 해당 선에서 멀리 떨어진다(왼쪽 상단 모서리 방향).

 분류 기준을 비교하는 한가지 방법으로 AUC(Area Under the Curve)를 측정이 있다. 완벽한 분류기는 ROC AUC의 크기가 1인 반면, purely random classifier는 0.5가 된다. scikit-learn은 ROC AUC를 계산하는 함수를 제공한다.


Tip

 ROC 커브와 Precision/recall 커브가 매우 유사하여, 어떤 것을 언제 써야되는지에 대해 결정하는 방법에 대해 궁금할 수 있다. 만약, positive class가 드물거나, False Negatives보다 False Positives에 대해 유의해야 되는 상황이라면, precision/recall 커브를 사용해야 한다. 그렇지 않은 상황이라면 ROC 커브를 사용한다. 

 예를 들어, 위의 roc_auc_score에서 0.95라는 점수를 보면 실제로 좋다고 생각 할 수 있다. 그러나 이것은 대부분 negative(5가 아닌)에 비해 positive가 너무 적기 때문이다.


 지금까지는 바이너리 즉 5와 5가 아닌 것에 대해 분류기를 훈련하였다. 

분류기의 성능을 측정하기 위해 교차검증(cross_validation)을 이용하였고, 필요에 따라 Precision/recall 곡선과, ROC 곡선 및 ROC AUC 점수를 통해 모델을 비교하는 방법을 알았다. 

 이제는 5와 5가 아닌 것에 대해 판단하는 것이 아닌, multi class 분류 방법에 대해 살펴보고자 한다.


Multiclass Classifier

 바이너리 분류기가 두 클래스를 구별하는 방식이라면, 멀티 클래스 분류기(다항)는 두 개 이상의 클래스를 구별하는 방식이다. 

Random Forest classifiers 나 naive Bayes classifiers같은 몇몇 알고리즘은 직접적으로 멀티 클래스를 다룰 수 있다.

그 외 Support Vector Machine이나 Linear classifiers과 같은 알고리즘은 엄격하게 바이너리 분류 방법이다. 그러나 멀티 바이너리 분류기를 이용하여 멀티 클래스 분류기를 수행할 수 있는 다양한 방법들이 존재한다.

 예를 들어, 숫자 이미지를 10개의 클래스(0에서 9까지)로 분류할 수 있는 시스템을 생성하는 방법 중 하나는, 10개의 바이너리 분류기를 각 숫자(0-탐지기, 1-탐지기 등)에 대해 하나씩 훈련 시키는 방법이 있다. 그다음 이미지를 분류하길 원할 때, 각 분류기로부터 decision score를 얻고, 가장 높은 점수를 출력하는 클래스를 선택할 수 있다. 이것을 one-versus-all(OvA) 전략이라고 한다. (또는 one-versus-the-rest)

 다른 전략으로는 모든 숫자의 쌍(pair of digits)에 대해 바이너리 분류기를 훈련시키는 방법이 있다. 0과 1을 구별하고, 0과 2를 구별하고, 1과 2를 구별하고 이를 모든 숫자에 대해 쌍으로 만드는 것이다. 이는 1대1(OvO) 전략이라고 한다. N개의 클래스가 있다면 N*(N-1) / 2 개의 분류기를 학습해야 한다. (숫자 10개이기 때문에 45개를 학습해야한다 OTL..) 이미지를 분류하려면 45개의 모든 분류기를 통해 어떤 클래스가 가장 많이 차지하는지 확인 해야 된다. OvO의 가장 큰 장점은 각각의 분류기를 구분하고자 하는 두개의 클래스를 위해 training set의 부분에 대해서만 학습하면 된다는 장점이 있다. (즉 45개의 분류기일지라도 1과 2를 분류하는 분류기의 경우 1과 2의 데이터에 대해서만 학습하면 된다) 

 Support Vector Machine 분류기와 같은 일부 알고리즘은 training set의 크기에 따라 가늠할 수 없기 때문에, 대규모의 training sets에서 조금의 분류기를 학습하는 것 보다 작은 training sets에서 많은 분류기를 훈련시키는 것이 빠르기 때문에 OvO 방식이 선호된다. 그러나 대부분의 바이너리 분류 알고리즘은 OvA가 선호된다.

 scikit-learn은 멀티 클래스 분류 작업에 바이너리 분류 알고리즘을 사용하려고 할 때 이를 감지하고 자동으로 OvA를 실행한다. (OvO를 사용하는 SVM 분류를 제외하고는)

 SGDClassifier를 이용해보자.

 매우 간단하다. 이 코드는 숫자 5랑 모든 타겟 클래스(y_train_5) 대신에 0에서부터 9까지의 original target 클래스인 y_train을 이용하여 학습하였다.  그런 다음 예측을 하였다. 

 scikit-learn은 실제로 10개의 바이너리 분류기를 학습하고, 이밎에 대해 decision scores를 얻었으며, 가장 높은 점수의 클래스를 선택하였다. 실제로 이것이 사실인지 확인하려면 decision_function() 함수를 호출하면 된다. 인스턴스 당 하나의 점수를 반환하는 대신 클래스 당 10개의 점수를 반환한다. 0부터 시작하기 때문에 6번째 값인 5가 가장 높은 점수임을 확인할 수 있다.

 만약 OvO 또는 OvA를 사용하고 싶다면 OneVsOneClassifier나 OneVsRestClassifier 클래스를 사용하면 된다. 

간단히 인스턴스를 생성하고 바이너리 분류기를 생성자에 보내주면 끝이다. 예를 들어, 아래의 그림은 SGDClassifier를 기반으로 OvO 전략을 이용한 멀티 클래스 분류기를 만든 것이다.

 이제는 배운 내용을 적용해보자. 분류기를 생성한 다음에는 무엇을 해야할까? 그렇다. 평가를 해봐야 된다. 이를 위해 교차 검증(cross_validation)을 적용해보자. cross_val_score() 함수를 사용하여 SGDClassfier의 정확도(accuracy)을 평가해보자.


 모든 test fold에서 85% 이상의 값이 나왔다. 정확도를 향상시킬 수는 없을까? 당연히 있다.

우리는 2장의 4-4에서 feature scaling에 대해 배우지 않았던가. 입력 값을 scaling 해보자.

단순 표준화(standardization)를 통해 성능이 90%이상까지 끌어 올릴 수 있었다.


Error Analysis

 우리는 제법 괜찮은 모델을 발견하였다고 가정해보자. 이제 이 모델을 향상시킬 방법을 찾고 싶다. 이를 위한 방법 중 하나는 오류 유형을 분석하는 것이다.  

 우선적으로, 앞 부분에 배웠던 confusion matrix를 살펴보자. 이전에 했던 것 처럼 cross_val_predict() 함수를 이용하여 예측을 수행 한 후, confusion_matrix() 함수를 호출 해야 한다.

숫자가 너무 많아 보기 힘들다. matplotlib의 matshow() 함수를 이용하여 confusion matrix의 이미지 표현을 보는 것이 더 편리하다. (대각선 값들이 심상치 않아보인다..)

위의 confusion matrix는 대부분의 이미지가 대각선에 위치하고 있기 때문에 상당히 잘 보인다. 즉, 올바르게 분류 되었다는 것을 의미한다. 5는 다른 자릿수보다 약간 더 어둡게 보인다. 이는 dataset에서 5의 이미지가 적게 있거나, 또는 분류기가 다른 숫자만큼 5에서 제대로 수행되지 않음을 의미할 수 있다. 실제로 둘 다 사실인지 확인할 수 있다. 

 오류에 관한 그림을 집중적으로 살펴보자. 먼저 confusion matrix의 각 값을 해당 클래스의 이미지 수로 나누어, 에러율을 비교할 수 있다. 

기억하자. 행은 실제 클래스를 나타내고 열은 예측 클래스를 나타낸다. 클래스 8과 9의 열은 꽤 밝은 것을 확인할 수 있다. 이는 8과 9를 잘 분류하지 못한다는 것을 의미한다. 마찬가지로, 클래스 8과 9의 행 또한 밝은 것을 확인 할 수 있는데, 이 또한 8과 9를 다른 숫자들과 종종 혼동이 된다는 것을 의미한다.

 이와는 반대로, 클래스 1의 경우, 어두운 것을 확인할 수 있다. 이는 대부분의 1이 정확하게 분류 된다는 것을 의미한다. 

오류는 완벽하게 대칭적은 아니다. 예를 들어, 실제는 5인데 예측은 8로 잘못 분류 된 것이 그 반대의 경우보다 더 많다.


 위의 두 개의 5*5 행렬은 3으로 분류된 것을 표시하고, 아래쪽의 두 개는 숫자 5로 분류 된 이미지이다. 

왼쪽 하단과 오른쪽 상단의 경우, 사람이 구분하는 것에도 문제가 있어보인다. 예를 들어 8행 1열의 5는 3처럼 보인다.
분류기가 잘못 분류를 한 이유를 이해하는 것은 상당히 어렵다. 그 이유는 선형 모델인 간단한 SGDClassifier 모델을 사용했기 때문이다. 클래스마다 가중치를 각 픽셀에 할당하고, 새로운 이미지를 확인할 때 가중치 픽셀 강도를 합산하여 각 클래스의 점수를 얻는다. 그렇기 때문에 3과 5는 단지 몇 픽셀만 다르기때문에 해당 모델은 쉽게 혼동 될 수 밖에 없다. 
 3과 5의 가장 큰 차이점은 하단의 arc(3과 5의 밑에부분인 둥근 부분)와 상단의 line(3과 5의 맨 위 선)을 연결하는 작은 선의 위치이다. 

 이 분류 기준은 이미지 이동 및 회전에 매우 민감하다. 따라서 혼란을 줄이는 한가지 방법은 이미지를 전처리하여 이미지가 중심에 있도록하고, 회전되지 않도록 하는 것이다. 이렇게 하면 다른 오류도 줄일 수 있다. 


Multilabel Classification

 지금까지의 각 인스턴스들은 하나의 클래스에만 할당 되었다. 경우에 따라 분류기는 각 인스턴스들에 대해 여러 클래스를 출력하도록 할 수 있다. 예를 들어 얼굴 인식 분류에 대해 생각해보자. 페이스북에서 단체 사진을 찍었다고 생각해보자. 이 사진에서 여러 사람을 인식해야 한다면 어떻게 해야할까? 물론 각각의 사람마다 하나의 라벨은 주어져야 된다. 분류기가 alice, bob, charlie의 얼굴을 인식하도록 학습했다고 가정해보자. 앨리스와 찰리의 사진만 있다면 [1,0,1]를 출력해야 된다. 이러한 multiple binary 라벨이 출력되는 분류 시스템은 multilabel classification system 이라고 부른다. 

 간단한 예를 살펴보자.

위의 코드는 각 자리수 이미지에 대해 두개의 타겟을 포함하는 multilabel 배열을 만든다. 첫 번째는 , 7 이상인 수인지 아닌지에 대해 나타내며, 두 번째는 홀수인지 짝수인지에 대해 나타낸다. 이 두 개를 합칠 때 np.c_ 를 사용하여 2열로 만든다.

 그 다음 KNeighborsClassifier 인스턴스를 만들고, multiple targets 배열을 이용하여 학습한다. 이제 우리는 예측을 할 수 있으며, 두 개의 라벨(label)이 출력 된다는 것을 알 수 있다.

위의 some_digit은 위에서부터 계속 사용했던 숫자 5다. 그렇기 때문에 앞의 False는 7이상이 아니기 때문에 출력된 것이며, 뒤의 True는 5가 홀수이기 때문에 true로 출력된다.

 

 multilabel 분류기를 평가하는 방법은 많이 있으며, 실제로 프로젝트에 따라 측정 항목을 선택하는 것도 다르다. 
예를 들어, 한가지 방법으로 각각의 라벨에 대한 F1 score를 측정한 다음, 간단하게 평균 점수만 계산하는 것이다. 아래 코드는 모든 라벨에서 F1 score의 평균을 계산한 것이다.

 이것은 모든 라벨이 똑같이 중요하다고 가정한 것이다. 특히, 만약 alice의 사진이 bob이나 charlie보다 많을 경우, alice의 사진에서 분류기의 점수에 더 많은 가중치를 주는 것이 좋다. 한가지 간단한 옵션은 각각의 라벨에 동일한 가중치(target label을 갖는 인스턴스의 수)를 부여하는 것이다. 이렇게 하려면 위의 코드에서 average = "weighted"를 설정하면 된다.

  • macro 평균은 클래스별 f1 score에 가중치를 주지 않는다. 클래스 크기에 상관없이 모든 클래스를 같은 비중으로 다룸

  • weighted 평균은 클래스별 샘플 수로 가중치를 두어 f1 score의 평균을 계산한다.이 값이 분류 report에 나타나는 값이다.

  • micro 평균은 모든 클래스의 FP(False Positive), FN(False Negative), TP(True Positive)의 총 수를 헤아린 다음 precision, recall, f1 score를 수치로 계산한다.

[파이썬 라이브러리를 활용한 머신러닝 책에서 macro/weighted/micro 평균 내용 발췌]
각 샘플을 똑같이 간주한다면 micro 평균을, 각 클래스를 동일한 비중으로 고려한다면 macro 평균 점수를 추천


Multioutput Classification

 이 장에서 논의 할 마지막 유형의 분류 작업은 multioutput-multiclass classification(또는 단순히 multioutput classification)이다. 이것은 간단히 각 라벨이 multiclass를 가질 수 있는 multilabel classification의 일반화이다. (즉 두 개 이상의 값을 가질 수 있음)

 이를 설명하기 위해 이미지로부터 노이즈를 제거하는 시스템을 만들어 보자. 입력 값으로 잡음이 많은 숫자 이미지를 선택 할 것이고, MNIST 이미지처럼 픽셀의 배열로 표현하는 숫자 이미지를 출력 할 것이다. 

 분류기의 출력 값은 multilabel(픽셀 당 하나의 라벨)이고, 각각의 라벨은 multiple 값 (픽셀 범위는 0에서 255)을 가질 수 있다. 

 

 먼저 Numpy의 randint() 함수를 사용하여 MNIST 이미지를 가져오고, 픽셀에 노이즈를 추가하여 학습 및 테스트 셋을 만들어보자. target 이미지는 원본 이미지이다.

 테스트 set으로부터 이미지를 살펴보자. 왼쪽에는 noisy 입력 이미지가 있고, 오른쪽은 타겟 이미지가 있다.

이제 분류기를 학습시키고 이 이미지를 clean하게 만들자.

 목표에 충분히 근접해 보인다. 이것으로 분류에 대한 결론을 마친다. 

본 3강을 통해, 이제 분류 작업에 적합한 metrics를 선택하고, 적절한 precision/recall tradeoff를 고르고, 분류기를 비교하는 방법을 알고, 좋은 분류 시스템을 구축할 수 있어야 된다.


하지만 아직 갈 길이 멀어 보인다.... 갈수록 어려워 지는 것 같은 기분이 들었다.....

4강에서는 모델을 학습하는 방법에 대해 다룬다.

반응형

02_End-to-End_Machine_Learning_Project(final).ipynb

책: O'REILLY의 Hands-On Machine Learning with Scikit-Learn & TensorFlow

URL: http://shop.oreilly.com/product/0636920052289.do

본문에 사용되는 사진들은 모두 위의 책에서 발췌

소스코드: https://github.com/ageron/handson-ml

틀린 내용이 있으면 언제든지 댓글 달아주세요! (오역은 어느정도 이해해주시길)


chapter2. End-to-End Machine Learning Project

 이번 장에서는 머신러닝의 프로젝트의 처음에서 끝까지 살펴보고자 한다. 주요 단계로는 아래와 같다.

  1. Look at the big picture.
  2. Get the data.
  3. Discover and visualize the data to gain insights.
  4. Prepare the data for Machine Learning algorithms.
  5. Select a model and train in.
  6. Fine-tune your model.
  7. Present your solution.
  8. Launch, monitor, and maintain your system.

Working with Real Data

 머신러닝을 공부하는데 있어 가장 좋은 방법은, 인공적으로 만든 데이터 셋이 아닌 실제 데이터를 가지고 실험하는 것이다. 우리가 사용할 수 있는 데이터는 상당히 많다. 

 이번 2장에서는 캘리포니아 주택 가격에 대한 데이터를 사용할 것이다. 해당 데이터는 1990년 캘리포니아 인구조사로부터 기반한다. (좀 오래 된 데이터이긴 하다..) 하지만 저자는 해당 데이터가 학습을 위해 많은 양을 포함하고 있고, feature에 대해 새로 추가하고 삭제하고 하는 기법을 사용한다고는 한다.

 

1. Look at the Big Picture

 Welcome to Machine Learning Housing Corporation!

 첫 번째 과제로는 캘리포니아 인구조사 데이터를 가지고 캘리포니아의 주택 가격의 모델을 만드는 것이다.

데이터로는 인구, 수입의 중간 값(median), 주택 가격의 중간 값(median), 그리고 캘리포니아의 지구(구역) 등이 측정 항목으로 포함되어 있다.

여기에서 지구(구역)은 'districts'로 약 600명에서 3,000명의 인구로 구성된 구역이다.

 만들어야하는 모델은 주어진 모든 측정 항목으로부터, 다른 districts의 주택 가격의 중간 값(median)을 예측할 수 있어야 된다.


1) Frame the Problem

 상사에게(지금 현재 Machine Learning Housing Corporation에 들어

와있다...) 가장 먼저 해야할 질문으로는 사업 목적에 대해 정확히 파악하는 것이다. 단순 모델을 만드는 것이 목적은 아닐 것이다. 어떻게 이 모델을 사용함으로써 이익을 추구할 수 있을까? 이 것은 상당히 중요한데 그 이유로는, 어떻게 문제화 할 것이며, 무슨 알고리즘을 선택할 것인지, 또한 모델을 평가할 때 무슨 성능 측정을 할 것인지 등에 대해 결정 할 수 있기 때문이다.

 아래의 그림(machine learning pipeline)과 같이, 주택 가격을 예측하여, 투자 할 가치가 있는지에 대해 평가 할 것이다.

 Pipelines

데이터 처리 컴포넌트의 시퀀스를 data pipeline 이라고 부른다. pipeline은 머신러닝 시스템에서 매우 일반적으로 사용되는데, 많은 데이터를 조작하고, 변환해야 되기 때문이다.

 컴포넌트는 일반적으로 비동기(asynchronously)로 실행된다. 각각의 컴포넌트들은 많은 양의 데이터를 가져와서 처리하고, 다른 데이터 스토어에 결과 값을 내보낸다. 그 후, pipeline의 다음 컴포넌트에서 이 데이터를 가져와서, 자신의 output에 내보내는 식이다. 

 각각의 컴포넌트는 독립적으로 수행되는데, 컴포넌트간의 인터페이스는 단순한 데이터 스토어다. 이를 통해, 시스템을 매우 쉽게 파악할 수 있으며, 여러 팀이 서로 다른 컴포넌트에 집중할 수 있게 된다. 

 그 다음 상사에게 물어 볼 질문으로는, 현재 솔루션(있을 시에)에 대해 묻는 것이다. 이는 문제를 해결함에 있어 통찰력을 줄 수 있다. 

 상사는 주택 가격을 측정함에 있어, 전문가에 의해 수동적으로 측정 되고 있다고 한다. 구역에 대한 최신 정보를 수집하고 있으며, 만약 주택 가격의 중간 값을 얻을 수 없을 경우, 복잡한 규칙을 사용하여 측정하고 있다고 한다. 이러한 방법은, 시간과 비용이 많이 소모되며, 측정 값도 좋지 않다. 

  이제 시스템을 설계해보자! 첫 째로, 틀을 만들어야 되는데 이것은 지도/비지도/강화학습 중 어떤 것이 적합할까? 또한, 분류, 회귀, 아니면 다른 것일까? 또한 batch 학습이 적합할까, 아니면 온라인 학습이 적합할까? 진행하기 전에 한번 생각해보는 시간을 가져보자.

 이것은 전형적인 지도학습의 문제이다. 또한, 이것은 주택 가격에 대한 측정이므로 회귀 문제가 적합하며, 더욱 정확하게는 multivariate 회귀 문제라고 할 수 있다. 그 이유는 다수의 feature를 사용하기 때문이다. 마지막으로 이 데이터는 연속적인 데이터가 들어오는 시스템이 아니기 때문에, 데이터가 급격하게 변하는 것을 조정할 필요가 없다. 그렇기 때문에 해당 시스템은 batch 학습이 적합하다.


2) Select a Performance Measure

 다음 단계로는 성능 측정(performance measure)을 선택하는 것이다. 일반적인 회귀 문제의 성능 측정으로는 평균 제곱근 편차(Root Mean Square Error, RMSE) 가 있다.

 

Notations

머신러닝에서 매우 일반적으로 사용되는 notations

  • m: 데이터(instance)의 수
  • x^(i): 데이터 셋에서 i번째의 모든 feature 값들의 벡터 (단, y^(i)값인 라벨은 제외) 
     예를 들어, 위도:33.91, 경도: -118.29, 중간 수입: 500만원 일 때, 주택 가격의 중간 값이 5억이라고 가정해보자.
     이 때, x^(1) = [33.91, -118.29, 500]^T(전치해서 벡터를 뜻함), y^(1) = 1 이 된다.
  • X: 데이터 셋의 모든 feature의 행렬
     x^1, X^2..... 들에 대해 행렬로 만든 것
  • h: 예측 함수, hypothesis라고 부름. 
     예를 들어, x^(i) 데이터의 feature 벡터가 주어졌을 때, 결과 값으로 예측 값인 y-hat^(i) =  h(x^(i))로 표현
  • RMSE(X,h): 가설 h를 이용하여 데이터를 측정하기 위한 cost 함수
    별거아닌데 작성하기가 어렵다..

 일반적으로 RMSE가 회귀 작업을 위한 성능 측정에 대해 선호하는 방법이지만, 일부 상황에 대해서는 다른 방법이 좋을 수 있다. 예를 들어, 많은 이상치 districts가 있다고 가정해보자. 이러한 경우에는, 평균 절대값 오차(Mean Absolute Error)가 이용 될 수 있다.

 RMSE와 MAE는 두 벡터 사이의 거리를 측정하는 방법이다. 

 

3) Check the Assumptions

 가설을 확인할 것. 이는 심각한 문제를 초기에 해결 할 수 있음. 예를 들어, 예측한 가격에 대해 실제 값이 아닌 "싸다, 보통이다, 비싸다"라고 카테고리화 시켜야 되는 문제였다면? 이는 회귀 작업이 아닌 분류 작업으로 바꿔야 될 필요가 있다. 다행히도, downstream system 팀원들에게 물어 본 결과, 카테고리가 아닌 실제 값이라고 한다! 다음 단계로 넘어가자!


2. Get the Data

 이 책은 jupyter notebook으로 실습을 한다. 본 포스팅에는 jupyter 설치 방법은 제외한다.


1) Download the Data

 데이터 fetch에 대해 소개한다.

데이터는 저장소로부터 불러오게끔 되어있으며, 사용하고 있는 머신에 다양성을 두기 위해 os를 import 하여 처리하고 있다. 

로컬 내 디렉토리가 없을 경우, 새로 생성된다. 다운 받는 파일이 tar 형식으로 압축되어 있기 때문에, tar파일에 대한 압축 해제 코드도 포함되어 있다.


 다음으로는 pandas를 통해, 데이터를 불러 올 수 있다. 함수를 정의해 놓음으로써, 편리하게 재 사용 할 수 있다.

위에서 tar파일을 압축 해제하면 csv파일이 생성 된다. 이 csv파일을 불러오는 것이다.

파일을 로컬 내 저장하고, 압축을 푸는 함수는 fetch_housing_data() 를 통해 호출 할 수 있고, 데이터를 pandas로 불러오는 함수는 load_housing_data() 를 통해 진행 할 수 있다.


2) Take a Quick Look at the Data Structure 

 jupyter notebook을 이용하여, 불러 온 화면은 아래와 같다.

총 20,640개의 데이터가 있으며, 10개의 컬럼, 즉 feature를 가지고 있다. 

주목해야 할 점은, ocean_proximity feature를 제외한 다른 feature들은 float64의 데이터 형식으로 되어있지만, ocean_proximity의 경우 string값으로 되어 있다는 점이다. 또한, total_bedrooms의 경우 다른 feature들은 20,640의 데이터를 가지고 있는 반면, 20,433개로 207개의 데이터가 손실이 있다. 이는 값이 들어 있지 않을 때, 처리되지 않기 때문이다. describe() 함수를 호출하면, 각각의 feature 들에 대해 개수나, 평균, 표준편차 등을 확인 할 수 있다.

 위의 ocean_proximity의 경우 string으로 되어 있다고 하였다. 이는 무엇을 의미하는 것일까? 

이것은 아마 categorical 속성이라는 것을 알 수 있다. (연속된 데이터로 이루어진 것이 아니기 때문에 regression으로 생각하지는 않을 것이다)

value_counts() 함수를 사용하여 ocean_proximity의 값들을 확인해 볼 수 있다. 5개의 값으로 구성되어 있음을 알 수 있다.

 데이터의 형태를 빠르게 확인해 볼 수 있는 히스토그램을 그려보자. 

 위 히스토그램에서 눈여겨볼 만한 사항으로는 median_income부분이 미국 달러로 표현되지 않았다는 것이다. 

또한 housing_median_age와 median_house_value 모두 상한 선을 가지고 있다는 것이다. 

마지막으로는 꼬리가 길다는 것이다. 이것은 몇몇 머신러닝 알고리즘에 있어 패턴을 인식하는 데 있어 어려움을 줄 수 있다.

추후 이러한 속성들을 종 모양의 분포(정규분포겠쥬?)를 가질 수 있도록 변형을 할 것이다.


 3) Create a Test Set 

 테스트 셋을 만드는 것은 이론적으로 매우 간단하다. 단순히 몇 개의 instance들을 랜덤으로 추출하면 된다. 일반적으로 테스트 셋은 전체 셋의 20%정도를 추출한다.

위의 방법은 잘 동작하지만, 문제가 있다. 만약 프로그램을 다시 돌린다면, 다른 테스트 셋이 생성된다.. 

이러한 문제를 해결하기 위한 방법 중 하나는 처음 돌렸을 때의 데이터를 저장하고, 이를 다시 불러오는 방법이다.

다른 방법으로는 seed 값을 설정해주는 것이다. 즉 np.ramdom.permutation을 호출하기 전에 seed값을 설정함으로써, 항상 같은 shuffled된 값들을 생성하는 방법이다.

 

 그러나 위의 두가지 방법 모두 새로운 데이터셋을 업데이트 하고 fetch 할 때 문제가 발생한다. 

이러한 문제를 해결하기 위한 방법으로는 각각의 인스턴스 식별자(identifier)를 사용하여 해당 인스턴스가 테스트 셋에 포함되어야 하는지에 대한 여부를 결정하는 것이다. 예를 들어, 각 인스턴스 식별자의 hash값을 계산한 후, hash의 마지막 값만 유지시킨다. 그 다음 51과 같거나 작을 경우 (256의 20%) 테스트 셋에 넣는다. 이러한 방식을 사용하면 데이터 셋을 새로 고치더라도 일관되게 유지 된다. 새로운 테스트 셋에는 새로운 인스턴스의 20%가 포함되겠지만, 이전 트레이닝에 사용된 셋의 어떠한 인스턴스들도 포함되지 않을 것이다.

 위의 방식으로 진행하기에는 아쉽게도 housing dataset에는 식별할 수 있는 unique한 값이 없다. 그렇기 때문에 간단한 방법으로 row index 번호를 unique한 식별자로 사용하고자 한다.

 아래의 그림을 보면 맨 왼쪽 컬럼에 index 열이 추가되었음을 확인할 수 있다. 이는 다른 행과 겹치지 않기 때문에 unique하다.

 train data와 test data로 구분하는 것은 아래와 같다.


  파이썬에서 머신러닝에 사용하는 라이브러리 중 가장 유명한 scikit-learn에도 위의 데이터를 나누는 함수를 제공한다.

가장 간단한 것으로는 train_test_split이 있다. 이것은 위의 split_train_test와 매우 유사하다. 

짧기 때문에 본문에 표시하고자 한다.

1
2
3
4
from sklearn.model_selection import train_test_split
train_set, test_set = train_test_split(housing, test_size=0.2, random_state=42)

#https://colorscripter.com/
cs

끝이다..... 뭐 처음부터 이런방식대로 사용하는건 편리하겠지만, 약간의 이해를 하기 위해서 훑어봤다라고 생각하면 좋지 않을까싶다. 그런데 이러한 라이브러리를 사용함에 있어, 필요한 부분은 버전업이 되면서 함수들이 달라질 수 있으므로 버전과 함수명을 체크하는 것이다. (예를 들어 scikit-learn의 17버전에는 train_test_split이라는 함수를 model_selection 부분에서 찾을 수 없었지만, 19버전에서는 사용할 수 있었다.)

 전문가들이 중간 주택 가격을 예측하기 위해서는 중간 소득이 중요하다 가정해보자. 중간 소득 히스토그램을 확인해보자.

 대부분의 값들이 2에서부터 5까지 밀집되어있다. 또한 몇몇은 6을 초과하고 있다. 각 데이터 집합에 편향되지 않은 인스턴스들을 갖는 것이 중요하다.


 아래의 그림은 중간 소득에 1.5로 나눈 값을 반올림 처리하고(소득 카테고리를 제한하기 위해), 5보다 큰 값에 대해서는 5로 합치는 작업을 수행한다.

 

 다음으로는 소득 카테고리 기반으로 계층화(stratified)된 샘플링을 수행할 준비가 됐다. Scikit-learn의 StratifiedShuffleSplit 클래스를 사용할 수 있다.

 

 이제 원 상태로 돌아가기 위해 income_cat 속성을 삭제하여야 한다.



3. Discover and Visualize the Data to Gain Insights

 지금까지는 전반적인 데이터의 구조와 테스트셋의 구성에 대해 살펴보았다. 이제 우리의 목표는 조금 더 깊게 살펴보는 것이다.


1) Visualizing Geographical Data

 우리의 housing data는 경도와 위도를 가지고 있기 때문에, scatter 그래프는 좋은 아이디어로 사용 될 수 있다.

 좌측의 그래프의 경우 구분이 잘 되지 않아, 오른쪽에 alpha 값을 주었더니 시각적으로 보기 편하다. 밀집되어 있는 부분은 미국의 LA나 San Diego 뭐 이런 데 근처라고 한다. (한국의 지도도 이렇게 나오면 어딘지 잘 모르겠는데, 미국은 .. 그냥 그러려니)


 이제 주택 가격에 대해 살펴보고자 한다. 

 cmap에 미리 정의된 것들은 아래 보이는 것처럼 상당히 많다.
(가끔 이름이 생각이 안날 때, 일부러 틀리게 적고 확인하는 꼼수를... )

jet는 파랑(낮은 값)색에서 빨강(높은 값)의 범위를 가지는 color map이다.

 위의 이미지에서 볼 수 있듯이, 주택 가격은 인구밀도와, 지역과 많은 관련성(예를 들면, ocean과의 밀접)이 있다는 것을 확인할 수 있다. 이것은 클러스터링 알고리즘을 사용하여 주요 클러스터를 감지하고, 클러스터 센터의 근접성을 측정하는 새로운 feature를 추가하는 데 있어 유용하게 적용 될 수 있다.


2) Looking for Correlations

 dataset이 매우 크지 않기 때문에, corr() 함수를 사용하여 모든 속성들의 pair 사이에 표쥰 상관 계수를 쉽게 계산할 수 있다.

그리고 각 feature들이 얼마나 주택 중간 가격(median house value)과의 상관 관계가 있는지 확인할 수 있다.


 상관 계수의 범위는 -1에서부터 1까지이다. 1과 가까울 수록 강한 양의 상관관계를 표현하며, -1과 가까울수록 강한 음의 상관관계를 표현한다. 0에 가까울수록 두 데이터간의 상관관계는 적다. 아래 그림을 보면, 이해하기 쉽다.


 속성들 간의 상관 관계를 체크하기 위한 다른 방법으로는 pandas 의 scatter_matrix 함수를 사용하는 것이다. 

모든 9개의 feature들은 각각에 대해 상관 분석을 하기 때문에, 많은 양의 그래프가 출력된다. 그렇기 때문에 위의 속성 중 상위 4개에 대해서만 표현하기로 하자.

 대각선에 있는 히스토그램 그래프들을 보자. 만약 pandas가 각각의 변수를 그 자체로 plotted 하게 되면, 직선으로 가득 차게되어 유용하지 않을 것이다. 그렇기 때문에, pandas는 각각의 속성에 대해 히스토그램으로 표현하고 있다.

위에서 주택가격과 상관 관계가 가장 높았던 것은 중간 소득(median income)이었다. 이는 1행 2열의 산점도인데 좀 더 살펴보자.

 아래의 산점도를 살펴보면 두 가지를 확인해 볼 수 있다.

첫 째로, 상관 관계가 상당히 강하다. 점들이 분산되어 있지 않고, 양의 상관 관계임을 확인할 수 있다.

둘 째로, $500,000 이상의 값들은 $500,000으로 맞춰진다. 그러나 이 산점도는 $450,000, $350,000, $280,000 등에서도 수평선을 확인할 수 있다. 알고리즘이 이러한 데이터의 이상점(quirks)을 학습하고 재현하는 것을 보호하기 위해, 해당 districts를 제거할 수 있다. 


3) Experimenting with Attribute Combinations

 머신러닝 알고리즘에 대한 데이터를 실제로 진행할 때, 다양한 속성들에 대해 조합을 시도해 볼 수 있다.

예를 들어, 총 districts에 있는 방의 총 개수는, 실제로 얼마나 많은 가구들이 존재하는지 모른다면 불필요한 정보일 수 있다.

실제로 원하는 것은 가구 당 방의 갯수이다.

 마찬가지로, 총 침실 수 자체만으로는 유용한 정보를 도출할 수 없다. 이 때 필요한 것은, 방의 개수와 비교하는 것이다. 

그리고 가구당 인구 또한 흥미로운 조합의 속성일 수 있다. 다음과 같이 새로운 속성을 만들어보자.


 나쁘지 않았다. 새롭게 추가된 방 개수당 화장실 수 속성은 총 방의 개수나 침술 수보다 더 관련이 높음을 알 수 있다. 

해석해보자면 침실의 낮은 비율이 집 값이 비싼거와 연관이 있고, 가구당 방의 개수는 districts의 총 방의 개수보다 더 관련이 있다. 

4. Prepare the Data for Machine Learning Algorithms

 이제 머신러닝 알고리즘을 위해 데이터를 준비하는 시간이다. 

처음으로는 training set에 대해 깨끗한 상태로 되돌려야된다.

1
2
3
4
5
housing = strat_train_set.drop("median_house_value", axis=1)
housing_labels = strat_train_set["median_house_value"].copy()
 
#https://colorscripter.com
 
cs

1) Data Cleaning

 대부분의 머신러닝 알고리즘은 손실된 feature값에 대해 잘 작동하지 않는다. 그렇기 때문에 이를 처리하기 위한 몇 가지 기능을 만들어야된다. 우선 2.2)에서 언급했던 total_bedrooms을 떠올려보자. 분명 20,640에서 207개가 손실된 20,433개만 가지고 있었다. 이를 수정해보자. 이를 위해 3가지 옵션이 있다.

  • Get rid of the corresponding districts.
  • Get rid of the whole attribute.
  • Set the values to some value (zero, the mean, the median, etc).

 DataFrame's의 dropna(), drop(), 그리고 fillna() 함수를 사용하면 쉽게 해결할 수 있다.

이름에서 알 수 있듯이, dropna는 nan 값들이 있는 데이터를 삭제 하는 방법

drop은 전체 속성의 값, 즉 total_bedrooms 열을 삭제, 마지막으로 fillna는 nan값들을 특정 선택하는 데이터로 채우는 것이다.

1
2
3
4
5
6
7
8
#option 1
housing.dropna(subset = ["total_bedrooms"])
#option 2
housing.drop("total_bedrooms", axis=1)    #여기에서 axis=1은 열을 뜻한다.
#option 3
housing["total_bedrooms"].fillna(median, inplace=True)    #inplace=True를 해줘야 데이터가 갱신된다.
 
#https://colorscripter.com/
cs

 

 만약 option 3을 선택한다면, training set의 중간 값을 계산해줘야 되며, training set의 빈 칸에 중간 값으로 채워줘야 된다.

Scikit-learn에서는 누락 된 값을 처리 할 수 있는 Imputer라는 편리한 클래스를 제공한다. 

먼저 Imputer 인스턴스를 생성하고, 각 속성의 누락 된 값을 해당 속성의 중앙값으로 대체하도록 지정해주면 된다.

1
2
3
4
from sklearn.preprocessing import Imputer 
imputer = Imputer(strategy ="median")
 
#https://colorscripter.com/
cs

 2.2)에서 언급했던 ocean_proximity가 어떤 특성이 있었는지 기억나는가. 그렇다. ocean_proximity는 non numeric으로 이루어져 있다. 중앙 값은 숫자 속성에서만 계산 될 수 있기 때문에 텍스트 속성 없이 데이터 사본을 만들어야 된다.

1
2
3
4
#숫자로만 이루어진 housing_num이라는 별도의 사본을 만듦
housing_num = housing.drop("ocean_proximity", axis = 1)
 
#https://colorscripter.com/
cs


 이제 fit() 함수를 사용하여 Imputer 인스턴스를 training data에 맞출 수 있다.

1
2
3
imputer.fit(housing_num)
 
#https://colorscripter.com/
cs


 Imputer는 단순히 각 속성의 중앙 값을 계산하고 그 결과를 statistics_ 인스턴스 변수에 저장한다. total_bedrooms 속성에만 값이 누락 되었었지만, 시스템이 작동 한 후에 새 데이터에 누락 된 값이 없는지에 대해 확신할 수 없기 때문에 모든 속성에 적용하는 것이 더 안전하다.

imputer.statistics_에 저장 된 값과 속성들의 중간값을 계산 한 것과 같음을 확인할 수 있다.


 

 이제 학습된 중앙값으로 누락된 값들을 대체함으로써 트레이닝 셋을 변환하기 위해 "훈련 된" imputer 를 이용할 수 있다.

결과물은 변환 된 feature 들을 포함한 Numpy 배열이다. 

 만약 pandas DataFrame으로 다시 되돌리고 싶다면 아래와 같다.


2) Handling Text and Categorical Attributes

 좀 전에 categorical 속성인 ocean_proximity를 삭제했었다. 그 이유는 텍스트로 구성 되어 있어 중간 값을 계산 할 수 없었기 때문이다. 많은 머신러닝 알고리즘은 숫자로 처리하는 것을 선호한다. 그럼 이러한 텍스트로 이루어진 것들은 사용할 수 없을까?

정답은 당연히 아니다. 이제 이 텍스트로 구성된 것을 숫자로 변환하는 작업을 해보자.

 Scikit-Learn에는 이러한 것들을 처리하기 위해 LabelEncoder 함수를 제공한다.

인코딩 된 값을 확인해보면 3,3,3....1,1,1 이라는 숫자를 확인 할 수 있다. 이는 1H OCEAN은 0, INLAND는 1... ISLAND는 4이다.


 위의 인코더의 문제점은, 머신러닝 알고리즘이 두 개의 근접한 값들이 거리가 있는 두 개의 값들보다 더 유사하다고 가정한다는 것이다. 이는 예를 들어 범주 0과 4가 범주 0과 1보다 더 유사할 수 있는 문제가 발생한다.

이러한 문제점을 해결하기 위한 방법으로 바이너리 속성을 부여하는 것이다. 이를테면 1H OCEAN이 1일 때 나머지 속성들은 0을 주는 방식이다. 이러한 방법을 one-hot encoding이라고 부른다.

즉, 1H OCEAN, INLAND, NEAR OCEAN, NEAR BAY, ISLAND 라는 5개의 각기 다른 값이 있을 때,  1H OCEAN이 1이면 10000,

NEAR OCEAN이 1이면 00100 식으로, 1은 (hot), 다른 것들은 0 (cold)가 되는 인코딩 방법이다. 하나만 hot이자나~~


 Scikit-learn은 integer categorical 값을 one-hot 벡터로 변환하는 OnehotEncoder를 제공한다. 주의해야 할 점은 fit_transform()은 2차원 배열을 기대하지만, housing_cat_encoded는 1차원 배열이라는 것을 주의해라. 그래서 우리는 재구성이 필요하다.


 결과물이 왜 numpy 배열이 아닌 sparce 행렬일까??? category가 수천 가지인 경우 매우 유용하게 적용 된다. one-hot 인코딩 후 수천 개의 열을 가진 행렬이 생성 된다. 이 행렬은 하나의 열인 1을 제외하고는 모두 0으로 채워진다. 이 0을 저장하기 위해 많은 메모리를 사용하는 것은 상당히 낭비가 아니겠는가. 그런데 이 sparce 행렬은 0이 아닌 요소의 위치만 저장한다. 
참 좋은 기능이다!


Scikit-learn에는 텍스트를 integer categories로 바꾸고 이 integer categories를 one-hot vectors로 바꿔주는 클래스 또한 제공함: LabelBinarizer


3) Custom Transformers

 Scikit-learn이 물론 유용한 transformers를 제공하고 있지만 custom 해야 할 필요가 있음.

Scikit-learn은 클래스를 생성하고 3개의 함수를 구현하는 것이 전부임
(3개의 함수란 fit(): self를 반환, transform(), 그리고 fit_transform()

 여기에서 transformer 함수는 하나의 하이퍼 파라미터로 add_bedrooms_per_room이 기본적으로  true로 설정되어 있다. 이러한 하이퍼 파라미터를 사용하면 해당 속성을 추가하여 머신러닝 알고리즘에 도움이 되는지에 대한 여부를 쉽게 확인할 수 있다.


4) Feature Scaling

 데이터를 적용하기 위해 가장 중요한 변형 방법 중 하나는 feature scaling이다. 특이한 경우를 제외하고는 대부분의 머신러닝 알고리즘은 매우 다른 scale에 대해 정상적으로 동작하지 않는다. housing data에 대해 상이한 scale을 확인해보자.

 total_rooms의 경우, 6에서부터 39,320 까지의 범위를 가진다. 이에 반해, median_income의 경우 0.5에서부터 15의 범위를 가진다.


 이러한 문제를 해결하기 위한 방법으로는 min-max scaling과 standardization이 있다.

  • Min-max scaling(많은 사람들은 정규화(normarlization)라고도 부른다)
    - 0에서부터 1까지의 범위로 만드는 방법으로 간단하다. 주어진 값에서 최소값을 빼주고, 최대값에서 최소값을 뺀 값을 나눠주면 된다.

    Scikit-learn에서는 MinMaxScaler를 제공한다. 한가지 재밌는 사항으로는 0-1의 범위를 원하지 않을 때, feature_range라는 하이퍼 파라미터를 제공해주기 때문에 범위를 설정해줄 수 있다.

  • Standardization
    - 위의 정규화 방식과 꽤 다르다. 먼저 평균 값을 빼주고(그렇기 떄문에 standardization값은 항상 평균값이 0이다), 분산(variance)로 나눠준다. 정규화와 달리 standardization은 특정 범위로 한정되지 않는다. 이 점은 몇몇 알고리즘에 문제가 될 수 있는데 그 중 하나는 neural network의 경우 input 값이 0에서부터 1까지의 값을 집어넣기 때문에 적합하지 않을 수 있다.
    하지만 장점으로는 이상점(outlier)에 덜 영향을 받는다는 것이다. 예를 들어, district의 중간 소득 값을 실수로 100이라고 가정해보자. Min-max scaling의 경우, 0-15의 범위로부터 0-0.15로 모든 다른 값들을 망칠 수 있다.
    Scikit-learn에서는 StandardScaler를 제공한다.

5) Transformation Pipelines

 데이터 변환에 있어, 많은 일련의 순서로 실행된다는 것을 확인해 볼 수 있었다. Scikit-learn에서는 Pipeline 클래스를 제공함으로써 이러한 변환에 있어 도움을 준다. 

 Pipeline 생성자는 이름과 추정자(estimator)가 쌍(pair)인 리스트로 구성되어 있다. 마지막 추정자를 제외하고는 반드시 transformers 를 가져야 한다. (즉, fit_transform() 함수를 가져야만 한다.)

 이름은 원하는 대로 지정이 가능하다. (두개의 밑줄 "__"을 포함하지 않는다면)

 pipeline's fit() 함수를 호출하면, 각 호출의 출력 값을 매개 변수로 전달하여 최종 추정량에 도달할 때까지 fit_transform() 함수를 순차적으로 호출하게 된다. 

 pipeline은 최종 추정자로써 동일한 함수를 제공한다. 예를 들어 마지막 추정자는 transformer인 StandardScaler다. 그렇기 때문에 pipeline은 모든 데이터 변환에 순차적으로 적용하는 transform() 함수를 가진다. (또한, fit()과 함께 transform()을 호출하는 대신에 사용했던 fit_transform() 함수를 가진다) 

 

 이제 숫자 열(numerical columns)을 numpy 배열에 수동적으로 추출하는 대신, pandas 데이터 프레임을 이용하여 직접 pipeline에 넣는다면 좋을 것이다. Scikit-learn에는 pandas 데이터 프레임을 다루는 방법은 없지만, 우리는 이 작업을 위해 custom transformer를 만들 수 있다.

 우리의 DataFrameSelector 함수는 원하는 속성을 선택하고, 나머지 부분은 삭제하며, Dataframe을 numpy 배열로 변환한다.

이를 통해, 우리는 쉽게 pandas 데이터 프레임을 이용하여 numerical values 만을 다룰 수 있는 pipeline을 작성할 수 있다.

pipeline은 숫자 속성을 가진 것만 선택할 수 있는 DataFrameSelecor로 시작하고, 이전에 논의한 전처리 단계를 거쳐야 된다. 또한 DataFrameSelecor를 사용하여 categorical 속성을 선택한 다음 LabelBinarizer을 적용하여 Categorical 속성에 대한 다른 pipeline을 쉽게 작성할 수 있다.

 이 두개의 pipeline을 하나로 합칠 수는 없을까?

당연히 존재한다. Scikit-learn에는 FeatureUnion 클래스를 제공한다. 리스트 형식의 transformer를 보내면 transform() 함수가 호출된다. 이 때 각각의 transformer가 병렬적으로 실행되며, 결과 값을 기다린다. 그 다음 각각의 transformer가 fit() 함수를 호출하면 최종 fit() 함수가 호출되어 결과를 합친다.


5. Select and Train a Model

 아... 여기까지는 잘됐다. 근데 모델 학습을 위한 housing_prepared에서 에러가 난다.

( TypeError: fit_transform() take 2 positional arguments but 3 were given)


 이 부분은 좀 더 확인이 필요할 듯.... 뒷부분은 학습데이터가 없기 때문에 진행 못함

상당히 찜찜해서 빠른 시일내에 확인해서 업데이트 예정 (9월 4일)


 해결했다. https://github.com/ageron/handson-ml/issues/75 이슈사항에 이미 등록되어 있었다.

아래 LabelBinarizerPipelineFriendly 클래스를 생성해준다.

다음으로는 cat_pipeline쪽에 기존의 LabelBinarizerPipeline부분을 LabelBinarizerPipelineFriendly로 대체해준다.


 이제 정상적으로 데이터를 뽑아보자. 이 화면을 그렇게 보고싶었다.........


1) Training and Evaluating on the Training Set

 이제 원없이 모델을 돌려보자. 첫 번째로는 선형 회귀 모델을 사용하여 학습시켜보자.

  예상치가 정확하지는 않지만(예를 들어, 첫 예측인 40%정도밖에 안됨) 작동은 된다. 

이제 평균제곱근오차(Root Mean Square Error, RMSE)를 측정하기 위해 Scikit-learn의 mean_squared_error 함수를 사용해보자.

 아무것도 안한 것보다는 좀 나아졌다. 그러나 좋은 점수는 아니다. 대부분의 districts의 중간 주택 가격이 $120,000에서 $265,000 이기 때문에 예측 에러가 $68,628이라는 숫자는 만족스럽지 못하다. 이러한 예는 학습 데이터의 underfitting 문제다. 

이러한 underfitting 문제가 발생했다는 것은 좋은 예측을 위한 충분한 정보가 제공되지 않거나, 모델이 강력하지 않다는 것을 의미한다. 이러한 underfitting을 해결하기 위한 방법으로는 보다 강력한 모델을 선택하거나, 더 좋은 feature들로 학습 알고리즘을 사용하거나, 모델의 제약을 줄이는 것이다. 

 이 모델은 정규화(regularized)되지 않았기 때문에 모델의 제약을 줄이는 것은 제외된다. 
(본문에는 없지만, 간단하게 얘기하면 정규화 즉 규제를 할 때, 알파값을 설정하여 모델의 규제를 완화시키거나 강화시킴으로써 언더피팅과 오버피팅 문제를 해결 하는 방법이 있음)

 

 더 많은 기능을 추가 할 수 있지만 우선 더 복잡한 모델을 사용해보자.

이번에는 의사 결정 ㄴ 회귀(Decision Tree Regressor)로 학습시켜보자. 이것은 강력한 모델로, 데이터에서 복잡한 비선형 관계를 찾을 수 있는 모델이다. (6장에서 더 자세히 살펴 볼 것이다.)

 0이란다. 딱봐도 이건 잘못되었다는 것을 알 수 있을것이다. 이러한 것을 지나치게 과적합되었다고해서 overfitting 이라 한다.

어떻게 확신할 수 있을까? 앞에서 살펴봤듯이, 확신 할 수 있는 모델이 생성되기 전까지 테스트 데이터를 건드리는 것은 원하지 않을 것이다. 이 때, 학습용 데이터의 일부를 훈련에 사용하고, 그 중 일부를 모델 검증용으로 사용하게 된다. 

즉, 학습용+테스트용 -> 학습용+검증용+테스트용 으로 된다는 것이다. 물론 학습용=학습용일부+검증용 이다.


2) Better Evaluation Using Cross-Validation

 의사 결정 나무 모델을 평가하는 방법 중 하나는, train_test_split 함수를 사용하여, 학습용 셋을 학습용 셋과 검증용 셋으로 분할 한 후, 분할 된 학습용 셋으로 모델을 학습시키고, 검증용 셋으로 모델을 평가하는 방법이 있다.

즉, train_test_split 함수 사용 -> 학습용셋을 학습용과 검증용으로 분할 -> 학습용으로 모델 학습 -> 검증용으로 모델 평가

위의 방법은 어렵지 않고 상당히 잘 작동한다.


 훌륭한 대안으로는 Scikit-learn의 cross-validation feature를 사용하는 것이다. 아래는 K-fold cross-validation 을 수행하는 그림이다. 이것은 무작위로 fold라고 불리는 10개의 subset으로 학습 데이터 셋을 분리한다. 그 다음 의사결정나무(decision tree) 모델로 10번 훈련시키고 평가 한다. 매 번 평가를 위해 다른 fold를 골라내고 또 다른 9개의 fold를 훈련시킨다.

그 결과는 10개의 평가점수를 포함한 배열로 표현된다.

이제 결정트리가 그 전 만큼 좋아 보이지는 않는다. 실제로 선형 회귀 모델보다 안좋아보인다. 교차 검증을 하면 모델의 성능 측정 뿐만 아니라 추정치의 정확성(즉, 표준편차) 또한 측정 할 수 있다는 것을 기억하자. 결정 트리는 +-2,728의 편차를 갖는, 약 71,265의 점수를 얻었다. 

 하나의 검증 셋만을 사용한다면, 이런 정보를 얻을 수 없다. 하지만 교차 검증은 여러 번 모델을 훈련시키는 비용이 발생하기 때문에 항상 가능한 것은 아니다.

  똑같은 방식으로 선형 회귀 모델에도 적용해보자.


 다음으로는 랜덤포레스트(Random Forest)를 실행해보자. 랜덤포레스트는 기본적으로 조금씩 다른 여러 결정 트리의 묶음이다. 랜덤 포레스트의 아이디어는 서로 다른 방향으로 과대적합된 트리를 많이 만들어내면 그 결과를 평균냄으로써 과대적합된 양을 줄일 수 있다는 것이다. 이렇게 하면 트리 모델의 예측 성능은 유지되면서 과대적합이 줄어드는 것이 수학적으로 증명 되었다.

랜덤 포레스트는 7장에서 더욱 자세하게 살펴 볼 것이다. 

 훨씬 더 좋은 결과를 얻었다. 그래도 아직 overfitting 되어 있다. 여기까지만 일단 진행하자.


Tip

파이썬의 pickle 모듈이나, sklearn.externals.joblib을 통해, Scikit-learn 모델을 쉽게 저장할 수 있다.


1
2
3
4
5
6
7
from sklearn.externals import joblib
 
joblib.dump(my_model, "my_model.pkl")
#나중에 불러 올 때
my_model_loaded = joblib.load("my_model.pkl"
 
#https://colorscripter.com/
cs


6. Fine-Tune Your Model

추후 진행 예정


반응형

책: O'REILLY의 Hands-On Machine Learning with Scikit-Learn & TensorFlow

URL: http://shop.oreilly.com/product/0636920052289.do

본문에 사용되는 사진들은 모두 위의 책에서 발췌

소스코드: https://github.com/ageron/handson-ml

틀린 내용이 있으면 언제든지 댓글 달아주세요! (오역은 어느정도 이해해주시길)


chapter1. The machine Learning Landscape


머신러닝이란 무엇인가?

General Definition

[Machine Learning is the] field of study that gives computers the ability to learn without being explicitly programmed.
(Arthur Samuel, 1959)

More engineering-oriented one

A computer program is said to learn from experience E with respect to some task T and some performance measure P,
if its performance on T, as measured by P, improves with experience E.

(Tom Mitchell, 1997)


 스팸필터로 예를 들어보자.

사용자에 의해 정의된 스팸 메일과, 일반적인 메일이 있다고 가정해보자.

이러한 스팸 메일과, 일반적인 메일은 training set이라고 불린다.

각각의 training examples은 training instance(or sample)라 불린다.


Task T: 스팸 메일인지에 대해 flag 부여

Experience E: training data (이전에 스팸인지 아닌지에 대한 정보)

Performance P: 정확히 메일을 분류 했는지에 대한 비율

(여기에서 P는 accuracy 라고도 불리며, 이는 종종 classification tasks에 이용된다.)


왜 머신러닝을 사용하는가?

 위의 예에서 얘기한 스팸필터에 대해 생각해보자.


 전통적인 프로그래밍 기법을 이용한 스팸필터는 아래와 같다.

 전형적으로 스팸메일에 사용되는 단어나 구문(예를 들면, "4U", "credit card", "free" 등)들을 보고, 탐지 할 수 있는 각각의 룰을 만든다. 이는 상당히 비효율적일 수 있는데, 각각의 룰들은 상당히 복잡한 룰이 될 수 있고, 이는 유지하기도 어려운 문제점이 있다.


다음은 머신러닝을 이용한 스팸필터이다.


 머신러닝 기반의 스팸필터 방식은 자동적으로 일반 메일과 비교하여, 스팸메일에서 빈번히 특이하게 사용하는 단어들의 패턴을 찾아준다. 프로그램은 훨씬 짧고, 유지하기 쉬우며, 정확도도 높다.


 위의 그림을 보면 붉은색의 Write rules과 녹색의 Data 부분과 Train ML algorithm 부분만 다르게 표시가 되어있는데, 이는 사람이 기존에 룰을 작성하였다면, 머신러닝 기반 학습방법은 "데이터를 통해 기계가 대신 학습해준다"라고 설명할 수 있다.


 이렇게 보면 "뭐가 그렇게 다를까?" 라고 생각해 볼 수도 있는데, 만약 스패머들이 "4U"라는 단어가 룰로 작성되었다는 것을 확인하고 "For U"라고 바꿨다고 생각해보자. 전통적인 스팸 필터 방식으로는 이렇게 변형 될 때마다 룰을 작성해야한다. 그와는 대조적으로 머신러닝 기법으로는 이러한 작업이 필요가 없게 된다.


 또한, 머신러닝 기법을 적용하면 대량의 데이터에서 보이지 않는 패턴들에 대해서도 발견할 수 있게 되는데, 이는 data mining 이라고도 불린다. 가령 아래의 그림과 같이, humans learn에 도움을 줄 수 있다고 해야할까나.



 위의 내용을 요약하자면 머신러닝이 좋은 이유에 대해 다음과 같다.

1) 기존의 수작업 또는 복잡한 룰을 머신러닝 알고리즘을 통해 간결한 코드로 좋은 성능을 낼 수 있다.

2) 변화가 심한 환경에서 머신러닝 시스템은 새로운 데이터를 채택할 수 있다.

3) 복잡하고 대량의 데이터에서 통찰력을 얻을 수 있다.

(그냥 머신러닝이 좋은 얘기를 구구절절 설명하고 있음)


머신러닝 시스템의 종류

1.  Whether or not they are trained with human supervision
(supervised, unsupervised, semisupervised, and Reinforcement Learning)

2. Whether or not they can learn incrementally on the fly

(online versus batch learning)

3. Whether they work by simply comparing new data points to known data points, or instead detect patterns in the training data and build a predictive model, much like scientists do

(instance-based versus model-based learning)


1. Whether or not they are trained with human supervision

1) Supervised learning

- 지도학습(감독학습이라고도 불림)은 쉽게 얘기해서 라벨(레이블)값을 주는 학습 방법이다.

 위의 training set을 보면 instance 즉 각각의 메일에 대해 정답을 부여하는 것이다. 

("이 메일은 정상 메일이다. 이 메일은 스팸 메일이다." 라는 정답)

전형적인 지도학습 방식은 분류(classification)이다. 즉, 메일이 스팸이냐 아니냐를 구분함.


 또다른 방식은 회귀(regression)가 있는데, 이는 쉽게 얘기하여 주식이나 집 값 같이 변동하는 연속적인 데이터들에 대해 예측하는 방식이라고 이해하면 된다.


지도학습에 자주 사용되는 알고리즘은 아래와 같다. (책에서 다룰 내용들)

  • K-Nearest Neighbors
  • Linear Regression
  • Logistic Regression (사실 Logistic Regression은 Logistic Classification이 더 적합)
  • Support Vector Machines
  • Decision Trees and Random Forests
  • Neural networks
    (모두 지도학습은 아님. autoencoders나 restricted Boltzmann machines같은 비지도 학습(Unsupervised)도 있고, deep belief networks 같은 준 지도학습(Semi-supervised)도 있음)

2) Unsupervised learning

- 비지도학습(무감독학습이라고도 불림)은 지도학습과 반대라고 생각하면 된다. 즉 라벨 값을 주지 않는 것이다. 기존의 라벨값을 주는 선생님이 있다고 했다면, 이번에는 선생님 없이 학습을 하는 방법이다.

 위의 그림 같이, 알려주는 사람이 없다.

 데이터의 특성에 따라 군집이 형성되는 것을 확인할 수 있다.

예를 들어, 내 블로그에 방문하는 사람들에 대해 군집화(Clustering) 알고리즘을 사용할 수 있는데, 영화를 좋아하는 방문자들, 쇼핑을 좋아하는 방문자들 등으로 분류를 할 수 있다. 또한, hierarchical clustering 알고리즘을 사용하여 영화 중에서도 드라마, 액션 등의 작은 그룹으로 분류 할 수 있다. 


비지도학습에 자주 사용되는 알고리즘은 아래와 같다.

  • Clustering
    • k-Means
    • Hierarchical Cluster Anaslysis(HCA)
    • Expectation Maximization
  • Visualization and dimensionality reduction
    • Principal Component Analysis (PCA)
    • Kernel PCA
    • Locally-Linear Embedding (LLE)
    • t-distributed Stochastic Neighbor Embedding (t-SNE)
  • Association rule learning
    • Apriori
    • Eclat

[으.... 주성분 분석, 커널 PCA 등 어려운 내용이 많다. 이전 자료 http://kkn1220.tistory.com/133에서 지도학습은 한번 훑어본 경험이 있지만, 비지도학습의 경우 제대로 학습을 하지 않았기에 벌써부터 걱정이다....]


 Visualization 알고리즘 또한 비지도학습의 좋은 예로 들 수 있다. 만약 복잡하고 라벨이 부여되지 않은 많은 데이터가 있을 때 이것을 2D(square)나 3D(cube)로 나타낼 수 있다. 

 이것과 관련이 있는 task는 차원축소(dimensionality reduction)가 있는데, 차원 축소의 목적은 데이터의 많은 정보에 대해 손실 없이 데이터를 간략하게 하는 것에 있다.

이것의 한가지 방법으로는 여러개의 feature들에 대해 상관 관계를 통해, 하나의 feature로 만드는 것이다. 이러한 것을 feature extraction이라고 부른다.


※Tip

 다른 머신러닝 알고리즘에 데이터를 넣기 전, 차원 축소를 이용하여 training data의 차원을 줄이는 것은 

좋은 시도일 수 있다. 그 이유는 속도를 빠르게 해주며, 디스크와 메모리를 덜 사용하게 하고, 또한 성능도 좋을 수 있기 때문이다.


 비지도 학습에도 군집화 말고 다른 중요한 것은 비정상 탐지(anomaly detection)을 말할 수 있다.

예를 들어, 평소와 다른 카드 거래를 감지하거나, 생산 및 제조 단계에서 감지할 수도 있다. 또는 다른 러닝 알고리즘에 적용하기 전 데이터셋으로부터 자동적으로 이상점(outlier)을 제거할 수도 있다.

아래의 그림은 정상 데이터를 통해 학습된 시스템이다. 새로운 데이터가 들어 왔을 때, 해당 데이터가 정상적인지, 아니면 비정상적인지 확인할 수 있다.


 마지막으로 비지도학습에서 중요한 task로 연관 규칙 학습(association rule learning, association analysis)이 있다.

연관 규칙 학습의 목적은 대량의 데이터에서 속성들(attributes) 사이에 관계를 발견하는 것이다.

예를 들어 슈퍼마켓을 운영하고 있다고 가정해보자. 사람들의 구매 내역에서 연관 규칙 학습을 통해 '바베큐 소스와 감자튀김을 구입한 사람들은 스테이크 또한 사는 경향을 보이더라.' 라는 결과를 얻을 수 있다. 그렇기 때문에, 운영자 입장에서는 이 음식들을 가까이 배치할 수 있다.


3) Semisupervised learning

준지도학습(실제로 준지도학습이라 부르는건 못들어본듯..)은 이름에서 얘기하듯이 지도학습과 비지도학습을 섞어놓았다고 생각하면 된다. 페이스북을 생각해보자. 일단 사용자는 페이스북에 자신의 친구나 가족들의 사진들을 업로드 할 수 있다. 이 때, 페이스북은 자동으로 사진들에 대해 A라는 사람과 B라는 사람을 인식할 수 있다. 여기까지는 비지도학습의 군집화(clustering) 부분이다. 그다음 사용자는 사진에 대해 A는 OOO이다. B는 XXX이다. 라고 라벨을 부여하게 된다. 이는 지도학습의 분류(classification)  부분이다. 이러한 방법은 사진을 검색하는데 상당히 유용하다.

페이스북에서 사진에 이사람은 누구입니까? 라는 것을 보았을 것이다. 결국 같은 맥락이다. 라벨을 많이 부여할수록 정확하게 인식하는 것은, 당연한 얘기


 대부분의 준지도학습의 알고리즘은 지도학습과 비지도학습의 결합(combinations) 이다.

예를 들어, deep belief networks(DBNs)는 restricted Boltzmann machines(RBMs) 라고 불리는 비지도학습에 기반한다.

RBMs는 비지도학습 방법에 의해 학습되며, 그 다음 전체 시스템은 지도학습 기법을 통해 fine-tuned 된다.


4) Reinforcement learning

- 강화학습은 위에서 언급한 것들과 매우 많이 다르다. 아래의 그림에서 보이는 agent가 주변 환경을 관찰한다. 

그 다음 환경에 맞는 선택을 하고 행동을 수행하게 되는데 이 때 정확한 행동에 대해서는 보상(rewards)을 하고, 반대로 정확하지 않은 행동에 대해서는 벌점(Penalty)을 부여하게 된다.

agent는 가장 좋은 정책(policy)을 스스로 학습하여, 주어진 상황에 맞게 행동할 수 있게 된다.

예로는 많은 로봇들이 어떻게 걷는지에 대해 학습시킬 때 사용 될 수도 있고, 2016년 3월에 이슈가 되었던 알파고가 있다. 알파고는 게임을 하는 동안에는 학습을 꺼두고, 단지 학습된 정책을 applying 했다는 것을 기억하라고 한다.


2. Whether or not they can learn incrementally on the fly

 머신러닝 시스템을 구분할 때 사용되는 다른 기준으로는, incoming data로 부터 점진적으로 학습할 수 있는 시스템인지 아닌지에 대한 분류이다.


1) Batch learning

- (일괄학습?)은 결론부터 말하자면 점진적으로 학습할 수 없는 시스템이다.

이것은 이용가능한 모든 데이터를 학습해야 한다. 그렇기 때문에, 일반적으로 많은 시간과 컴퓨팅 자원을 소모한다. 

시스템이 일단 학습이 되면, 더이상의 학습이 없이 적용이 된다. 이것은 offline learning 이라고 불린다.

만약 새로운 스팸메일 유형을 발견하여, batch learning 시스템에 적용을 원한다고 생각해보자. 이 때, 단순 새로운 데이터에 대한 것을 학습시키는 것이 아니라 기존 데이터 또한 학습시켜야 한다. 그 다음 기존 시스템을 중단하고, 새로운 시스템으로 교체를 해야 한다.

 다행인지는 모르겠지만, 왜 머신러닝을 사용해야 하는가? 부분에서 자동화 부분을 얘기했듯이, 전체 프로세스는 자동화 처리할 수는 있다. 그렇지만 이러한 시스템을 새로 동작하기 위해서, 기존 데이터까지 같이 학습을 시켜야 되는데 이 때, 시간과 자원을 소모해야 한다. 변동이 심한 데이터일 경우는 어떻겠는가... 이럴 때에는 batch learning이 적합하지 않다.


2) Online learning

- 온라인 학습은 연속적으로(각각이든 mini-batches로 불리는 소그룹이든) 들어오는 데이터에 대해 점진적으로 학습할 수 있는 시스템이다. 그렇기 때문에 각각의 학습 단계는 빠르고 적은 리소스를 사용하게 된다. 

 batch learning과는 달리 연속적인 데이터(예: 주가) 에 대해 상당히 유용하게 사용될 수 있으며, 즉 빠르게 대체할 수 있다. 이는 또한 한정된 컴퓨팅 리소스에 대해서도 좋은 학습 방법이다. 

새로운 데이터에 대해서만 학습을 하는 방식이기 때문에 기존의 것들은 버릴 수 있다.(기존으로 롤백 할 일이 없다면..)


 위의 그림처럼 온라인 학습 알고리즘은 또한,  하나의 기계의 메인 메모리로만 처리할 수 없는 대량의 데이터셋에도 이용 할 수 있다.(이를 out-of-core learning 이라고도 부른다). 알고리즘은 데이터의 부분을 load하며, 부분적 데이터를 각각 돌리고, 이를 전체 데이터를 돌릴 때까지 반복한다.


 온라인 학습 시스템에서 가장 중요한 파라미터 중 하나는 어떻게 변화하는 데이터를 빠르게 적용할 수 있냐는 것이다. (이를 learning rate라고 부른다.)

 만약 learning rate를 높게 설정하면, 시스템은 빠르게 새로운 데이터를 적용할 것이다. 그러나 이러한 방식은 기존 데이터를 빠르게 잊어버리는 경향을 보인다.

 반대로 learning rate를 낮게 설정하면, 시스템은 내성?(inertia)이 생겨 느리게 학습 될 것이지만, 새로운 데이터의 노이즈 값에 덜 반응하게 될 것이다.

 온라인 학습 시스템에서 가장 큰 도전은 '만약 bad한 데이터가 시스템에 유입될 때, 시스템 성능이 서서히 감소'하는 것이다. 이러한 위험을 감소시키기 위해, 시스템을 면밀히(closely) 모니터링 해야하며, 만약 성능이 저하되는 것을 확인했을 때 즉시 학습을 중단하여야 한다.(가능하면 이전 상태로 돌려놓는 것이 좋다.)


※Warning

 온라인 학습 방법 역시 offline으로 수행된다... 그렇기 때문에 온라인이라는 용어는 혼동될 수 있다.

온라인 학습 방법은 incremental learning으로 생각하면 된다.


3. Whether they work by simply comparing new data points to known data points, or instead detect patterns in the training data and build a predictive model, much like scientists do

 마지막으로 머신러닝 시스템을 분류하는 방법으로는 어떻게 데이터들을 일반화(generalize)하는 것이다.

 대부분의 머신러닝 tasks는 예측하는 것이다. 즉 학습 데이터(training examples)가 주어졌을 때, 시스템은 이전에 보지 못했던 examples에 대해 generalize할 필요가 있다. 

 학습데이터를 잘 분류하는 것은 좋은 일이지만, 불충분하다. 결국 우리의 목적은 새로운 데이터들을 얼마나 잘 분류할 수 있는지에 대해 성능이 좋아야 되기 때문이다.


1) Instance-based learning

(이 부분은 한글로 번역하기 애매한 부분들이 있어 영어로 작성)

 Possibly the most trivial form of learning is simply to learn by heart. If you were to create a spam filter this way, it would just flag all emails that are identical to emails that have already been flagged by users - not the worst solution, but certainly not the best.

 Instead of just flagging emails that are identical to known spam emails, your spam filter could be programmed to also flag emails that are very similar to known spam emails. This is requires a measure of similarity between two emails. A(very basic) similarity measure between two emails could be to count the number of words they have in common. The system would flag an emails as spam if it has many words in common with a known spam email.

 This is called instance-based learning: the system learns the examples by heart, then generalizes to new cases using a similarity measure.

 그림을 보니 결국 K-NN을 얘기하는 것 처럼 보였다. 그냥 기존의 학습 데이터에 새로운 데이터가 추가되었을 때, 데이터의 유사성을 측정하여 분류를 하는 것으로 이해했다. 


2) Model-based learning

데이터 셋으로부터 Generalize하는 다른 방법으로는 이러한 데이터들을 가지고 모델을 만드는 방법이다. 그 다음 생성 된 모델을 가지고 예측을 하는 것이다.

그렇다. 위의 Instance-based learning과 차이가 보인다. Instance based learning의 경우 새로운 instance 값이 들어왔을 때, 각각의 Training Instances들과 유사성을 측정을 해야한다. 그렇지만 밑의 Model-based learning의 경우 생성 된 모델에 새로운 instance 값이 들어왔을 때, 해당 영역으로 분류를 할 수 있다. 모델을 만드는 방법은 다음 챕터부터 차근차근 책에서 나온다.


Main Challenges of Machine Learning

머신러닝을 돌리기 위해 몇가지 나쁜 사례에 대해 얘기하고 있는데, 이부분은 가볍게 읽어보고 넘김

- 불충분한 학습 데이터의 양, 제각각의 Feature, 학습 데이터의 over/under fitting 등에 대해 소개

  


chapter1에서는 머신러닝이 무엇인지, 머신러닝이 왜 필요한지, 머신러닝의 종류가 무엇인지 등 머신러닝의 전반적인 부분에 대해 소개하고 있었다. chapter2에서는 End-to-End Machine Learning Project라는 주제로 진행하게 되는데, 머신러닝 데이터를 학습하기 전 데이터를 어떻게 수집하는지, 전처리는 어떻게 하는지에 대한 프로세스 설명이 될 것 같다.

반응형

http://kkn1220.tistory.com/133

파이썬 라이브러리를 활용한 머신러닝 책을 보던 중, 정확한 이해 없이 진행하는 것은 무의미하다고 판단하여 
책을 변경하였다. 위의 책도 물론 좋지만, 어느정도 머신러닝 알고리즘에 대해 이해하는 사람에게 더 유효 한 것 같다.


O'REILLY의 Hands-On Machine Learning with Scikit-Learn & TensorFlow라는 유명한 책인데, 이 책은 우선 영어다...

번역본도 나올 것 같지만, 예상 할 수 없어 아마존 킨들에서 바로 구입하였다. 아무래도 책을 계속 가지고 다니기는 어려움이 있어 바로 읽을 수 있는 킨들로 구매를 하였다.

(https://www.amazon.com/Hands-Machine-Learning-Scikit-Learn-TensorFlow/dp/1491962291/ref=sr_1_1?ie=UTF8&qid=1503911665&sr=8-1&keywords=hands+on+machine+learning+with+scikit+learn+and+tensorflow)


총 16강으로 되어 있으며, github는 아래와 같다.

https://github.com/ageron/handson-ml


전제조건으로는 

1) 파이썬 - 특히 numpy, matplotlib

-> http://learnpython.org/

2) Jupyter

-> 2장에서 설치 방법 및 기본에 대한 가이드가 나옴

3) 수학적 지식(미적분, 선형대수, 확률, 통계)

-> (선형대수) 모든 것을 알기에는 어렵다!!!! 한양대 이상화 교수님의 강의를 추천하는데, 그냥 벡터 및 행렬을 다루는데 중점적으로 가우스 소거법이나, 선형독립, 기저벡터, 벡터 투영, 함수공간 등에 대해 봤다. (증명까지는....skip)
(https://www.youtube.com/playlist?list=PLSN_PltQeOyjDGSghAf92VhdMBeaLZWR3)

-> (통계) 역시 한양대 이상화 교수님 강의를 추천. 적분을 통한 증명은 너무 어려워서... 확률 변수 정의, 누적 확률분포를 미분하면 확률밀도분포가 나오는 정도의 개념을 확인. 

(http://www.kocw.net/home/search/kemView.do?kemId=1056974)

-> 머신러닝을 시작하기도 전에 포기할 것 같아서.. 미적분이나 확률 같은 경우에는 일단은 스킵하였다.

개인적으로 이 책을 보기 전에 머신러닝 강의를 듣는 것을 추천하고 싶다.
-> 개인적으로 머신러닝에 대해 김성훈 교수님의 모두의 딥러닝을 듣는 것을 추천
(https://www.youtube.com/playlist?list=PLlMkM4tgfjnLSOjrEJN31gZATbcj_MpUm)

-> 두 번째로는 인공지능 및 기계학습 개론 1,2 의 카이스트 문일철 교수님 강의를 추천(http://kooc.kaist.ac.kr/machinelearning1_17)

-> 위의 강의를 수강한 후 위에서 언급한 파이썬 라이브러리를 활용한 머신러닝 책을 보던 중에, 좀 더 자세히 살펴보고자 해당 책을 읽고자 한다.


해당 책의 로드맵은 아래와 같다.

Part1. The Fundamentals of Machine Learning

- What is Machine Learning.

- The main steps in a typical Machine Learning Project.

- Learning by fitting a model to data.

- Optimizing a cost function

- Handling, cleaning, and preparing data.

- Selecting and engineering features.

- Selecting a model and tuning hyperparameters using cross-validation.

- The main challenges of Machine Learning, in particular underfitting and overfitting (the bias, variance tradeoff)

- Reducing the dimensionality of the training data.

- The most common learning a algorithms (Linear/Polynomial/Logistic Regression, K-NN, SMV, DT, Random Forest, Ensemble methonds)


Part2. Neural Networks and Deep Learning

- What are neural nets. what are they good for.

- Building and training neural nets using Tensorflow.

- The most important neural net architectures (CNN, RNN, LSTM etc)

- Techniques for training deep neural nets.

- Scaling neural networks for huge datasets.

- Reinforcement learning.


Part1에서는 주로 전반적인 머신러닝 알고리즘 및 데이터 전처리, feature 선택 등에 대한 내용을 담고 있다.

Part2에서는 인공신경망과 딥러닝에 대한 내용을 소개하고 있다.


책이 두꺼워서 꽤나 오래 걸리지 않을까 싶다..................

반응형

이 글은 파이썬 라이브러리를 활용한 머신러닝 책을 본 사람에게만 유효. (안드레아스 뮐러, 세라 가이도 지음. 박해선 옮김. O'REILLY)

파이썬 라이브러리: scikit-learn

jupyter notebook을 제공하기 때문에, 파이썬 코드나, 각각에 대한 그래프를 확인 할 수는 있지만, 

글의 경우 잊어먹기 쉽기 때문에, 소장을 위한 포스팅 

교재 소스 코드: https://github.com/rickiepark/introduction_to_ml_with_python/


2장. 지도학습


지도학습에는 분류와 회귀가 있음.

- 분류는 미리 정의된, 가능성 있는 여러 클래스 레이블 중 하나를 예측.

  이진 분류(binary classfication), 다중 분류(multiclass classfication)으로 나눌 수 있음.

- 회귀는 연속적인 숫자, 또는 프로그래밍 언어로 말하면 부동소수점수(수학 용어로는 실수)를 예측


지도학습 알고리즘 모델 요약


1) KNN: 작은 데이터셋일 경우, 기본 모델로서 좋고 설명하기 쉬움.

- 훈련 데이터셋을 그냥 저장하는 것이 모델을 만드는 과정의 전부. 별도의 학습이 필요 없음

- 새로운 데이터 포인트에 대해 예측할 땐 알고리즘이 훈련 데이터셋에서 가장 가까운 데이터 포인트, 즉 '최근접 이웃'을 찾음

  (scikit-learn에서 classfication, Regression 모두 지원)


- 매개변수: 중요한 매개변수는 2개. 데이터 포인트 사이의 거리를 재는 방법과 이웃의 수 (실제로 이웃의 수는 3,5개 정도로 적을 때 잘 작동하지만, 조정 필요) 거리를 잴 때, 유클리디안 거리 방식 사용

- 장점: 이해하기 매우 쉬운 모델.

- 단점: 전처리 과정이 중요. 훈련 세트가 매우 크면(특성의 수나 샘플의 수가 클 경우) 예측이 느림. 현업에서는 많이 사용 안함


- 데이터 셋: from sklearn.datasets import load_breast_cancer, from sklearn.datasets import load_boston

- 라이브러리

- graph example: mglearn.plots.plot_knn_classification(n_neighbors=<number>)

     mglearn.plots.plot_knn_regression(n_neighbors=<number>)

- library: from sklearn.neighbors import KNeighborsClassifier

from sklearn.neighbors import KNeighborsRegressor



2) Linear Model: 첫 번째로 시도할 알고리즘. 대용량 데이터셋 가능. 고차원 데이터에 가능.

- 선형 회귀(=LSE): 예측과 훈련 세트 사이에 있는 y 사이의 평균제곱오차(mean squared error)를 최소화 하는 파라미터 w, b를 찾음

- w(가중치:weight 또는 계수: coefficient), b(편향:offset 또는 절편:intercept)

- 평균제곱오차는 예측값과 타깃값의 차이를 제곱하여 더한 후에 샘플의 개수로 나눔

- 선형 회귀는 매개변수가 없는 것이 장점이지만, 그래서 모델의 복잡도를 제어할 방법도 없음

- 릿지 회귀(Ridge): 회귀를 위한 선형 모델로 최소적합법(Least Squares Estimation)에서 사용한 거과 같은 예측 함수 사용

- 하지만 릿지 회귀에서의 가중치(w) 선택은 훈련 데이터를 잘 예측하기 위해서 뿐만 아니라, 추가 제약 조건을 만족시키기 위한 목적도 있음. 가중치의 절대 값을 가능한 작게 만드는 것임. 다시 말해서 w의 모든 원소가 0에 가깝게 되길 원함. 직관적으로 생각하면 이는 모든 특성이 출력에 주는 영향을 최소한으로 만듦(기울기를 작게 만듦) 이러한 제약을 규제(Regularization)이라고 함. 

- 릿지 회귀에 사용하는 규제 방식을 L2규제라고 함

- 수학적으로 릿지의 계수의 L2노름(norm)의 제곱을 패널티로 적용

- 평균제곱오차 식에 아래의 식이 추가 됨

 (카이스트 문일철 교수님 강의를 보면 알파가 알파/2로 되어있음)

- 알파 값을 크게 하면, 패널티의 효과가 커지고(가중치 감소), 알파 값을 작게 하면 그 반대가 됨.

- 선형 회귀보다, 모델이 덜 자유롭기 때문에 과대 적합이 적어짐.

즉, 모델의 복잡도가 낮아지면 성능은 나빠지지만 더 일반화 된 모델

- 알파 값의 매개변수를 조정하여 훈련 세트의 성능 대비 모델을 얼마나 단순화 할지 지정할 수 있음.

- 알파값을 줄이면 계수에 대한 제약이 그만큼 풀리게되고, 아주 작은 알파 값은 선형 회귀로 만든 모델과 같아짐

- 라쏘 회귀(Lasso): 선형 회귀에 규제를 적용하는 데 Ridge의 대안으로 Lasso가 있음. 릿지와 같이 라쏘 또한 계수를 0에 가깝게 만듦

- 라쏘 회귀에 사용하는 규제 방식을 L1규제라고 함

- 라쏘의 계수 벡터의 L1노름을 패널티로 사용. 다른 말로 하면 계수의 절대값의 합

- 평균제곱오차 식에 아래의 식이 추가 됨

- 릿지와 마찬가지로 알파 값을 크게 하면 패널티의 효과가 커지고(가중치 감소), 작게 하면 그 반대가 됨

출처: kooc.kaist.ac.kr 인공지능 및 기계학습 개론1 (6강 Regularization 부분)

위의 그림을 보면 lasso의 경우 단일 부분만 겹치는 것을 확인할 수 있다. Ridge의 경우 제곱식이기 때문에 원의 형태로 모델이 생성되는데, 그렇기 때문에 겹치는 부분이 많음을 확인할 수 있다. 이는 즉 특성이 많고 일부분만 중요하다고 생각될 때에는 Lasso, 그렇지 않다면 Ridge모델을 선택하는 것을 확인할 수 있다.



※ 과소 적합을 줄이기 위해 alpha값을 줄여, 패널티의 효과를 줄임(가중치 증가) 

그러나 alpha값을 너무 낮추면 규제의 효과가 없어져 과대 적합이 된다. Linear Regression과 같은 모델이 됨

실제 두 모델 중 보통은 릿지 회귀를 선호함. 하지만 특성이 많고 그 중 일부분만 중요하다면 Lasso가 더 좋은 선택일 수 있다.

또한 분석하기 쉬운 모델을 원한다면 Lasso가 입력 특성 중 일부만 사용되므로 쉽게 해석할 수 있는 모델을 만들어 줄 것이다.

(scikit-learn은 Lasso와 Ridge의 패널티를 결합한 ElasticNet도 제공함. 실제로 가장 좋은 성능을 내지만 L1/L2규제를 위한 매개변수 두 개 조정 필요)


※Logistic Regression, SVM은 알파 값이 아닌 C값을 사용. Ridge와 마찬가지로 L2규제를 사용.

- 규제의 강도를 결정하기 위한 매개변수는 C.

- 위의 알파와 반대로 C의 값이 높아지면 규제가 감소함.다시 말해 매개변수로 높은 C값을 지정하면 훈련세트와 가능한 최대로 맞추려하고, 반대로 C값을 낮추면 모델은 계수 벡터(w)가 0에 가까워지도록 만듦

-> alpha값을 크게 하면 w가 작아지고, C를 작게 하면 w가 작아진다.

w가 작아진다는 것은, 데이트 포인트 중 다수에 맞추려고 하는 반면, w가 커지면 각각 데이터 포인트를 정확히 분류하려고 노력할 것이다.

응 교수님의 2차식과 9차식을 생각해보자. 9차식은 w가 크기 때문에 엄청 난잡한 그래프가 그려지지 않았던가..... 


- 매개변수

- 보통 C와 alpha값은 로그스케일로 최적치를 정한다. (예: 0.01,0.1,1,10)

- L1, L2규제를 정해야 한다. 중요한 특성이 많지 않다고 생각하면 L1규제를 사용. 그렇지 않으면 기본적으로 L2규제 사용

- 장점: 학습 속도가 빠르고 예측도 빠르다. 매우 큰 데이터셋과 희소한 데이터셋에서도 잘 작동한다.

- 단점: 예측이 어떻게 만들어지는지 비교적 쉽게 이해할 수 있지만, 계수의 값들이 왜 그런지 명확하지 않을 때가 있음.

   저 차원 데이터셋 일 때에는 다른 모델이 일반화 성능이 더 좋음


- 데이터 셋: mglearn.datasets.load_extended_boston(), mglearn.datasets.make_forge(), 

   from sklearn.datasets import load_breast_cancer

- 라이브러리

- example: mglearn.plots.plot_linear_regression_wave()

- library: from sklearn.linear_model import LinearRegression        //선형 회귀

from sklearn.linear_model import Ridge                         //Ridge회귀

from sklearn.linear_model import Lasso                         //Lasso 회귀

        from sklearn.linear_model import LogisticRegression    //Logistic 회귀

from sklearn.svm import LinearSVC                               //support vector machine (c는 classifier)



3) Naive Bayes: 분류만 가능. 선형 모델보다 훨씬 빠름. 대용량 데이터셋과 고차원 데이터에 가능. 선형모델보다 덜 정확

- 매개변수: 모델의 복잡도를 조절하는 alpha매개변수 하나를 가지고 있음 (alpha값이 크면 완만해지고, 모델의 복잡도는 낮아짐)

그러나 성능 변동은 비교적 크지 않아...

- 장점: 선형 모델과 비슷함. 훈련과 예측 속도가 빠르며 훈련 과정을 이해하기 쉬움.

희소한 고차원 데이터에서 잘 작동하며, 비교적 매개변수에 민감하지 않음

선형 모델로는 학스 시간이 너무 오래 걸리는 매우 큰 데이터셋에는 나이브 베이즈 모델을 시도해볼 만하며 종종 사용됨.

- 단점: 분류밖에 안된다?



4) Decision Tree: 매우 빠름. 데이터 스케일 조정이 필요 없음. 시각화하기 좋고 설명하기 쉬움.

- 결정트리는 분류와 회귀 문제에 널리 사용하는 모델. 기본적으로 결정 트리는 결정에 다다르기 위해 예/아니오 질문을 하면서 학습

- 일반적으로 트리만들기를 모든 리프 노드가 순수 노드가 될 때까지 진행하면 모델이 매우 복잡해지고, 훈련데이터에 과대 적합됨

  순수 노드로 이루어진 트리는 훈련 세트에 100% 정확하게 맞는 것을 의미. 즉 훈련 세트의 모든 데이터 포인트는 정확한 클래스의 리

  프 노드에 있음. 이렇게 될 경우에는 결정 경계가 클래스의 포인트들에서 멀리 떨어진 이상치 하나에 민감하게 작용됨

- 과대 적합을 막기 위해서는 두 가지가 있음

- 사전 가지치기(pre-pruning): 트리 생성을 일찍 중단하는 전략

- 사후 가지치기(post-pruning 또는 pruning): 트리를 만든 후 데이터 포인트가 적은 노드를 삭제하거나 병합하는 전략

(scikit-learn에서는 사전 가지치기만 지원)


- 매개변수: 트리가 완전히 만들어기 전에 멈추게 하는 사전 가지치기 매개변수. 보통은 사전 가지치기 방법 중 max_depth,

max_leaf_nodes 또는 min_samples_leaf중 하나만 지정해도 과대적합을 막는 데 충분

- 장점: 만들어진 모델을 쉽게 시각화할 수 있어서 비전문가도 이해하기 쉬움. 또한 데이터의 스케일에 구애 받지 않음.

각 특성이 개별적으로 처리되어 데이터를 분할할하는 데 데이터 스케일의 영향을 받지 않으므로 결정트리에서는 특성의 정규화나 표준화 같은 전처리 과정이 필요 없음. 특히 특성의 스케일이 서로 다르거나 이진 특성과 연속적인 특성이 혼합되어 있을 때도 잘 작동

- 단점: 사전 가지치기를 사용함에도 불구하고 과대적합되는 경향이 있어 일반화 성능이 좋지 않음.


- 데이터 셋:  from sklearn.datasets import load_breast_cancer

- 라이브러리

- graph example: mglearn.plots.plot_animal_tree()

- library: from sklearn.tree import DecisionTreeClassifier, from sklearn.tree import DecisionTreeRegressor



5) Random Forest: 결정 트리 하나보다 거의 항상 좋은 성능을 냄. 매우 안정적이고 강력함. 

데이터 스케일 조정 필요없음. 고차원 희소 데이터에는 잘 안 맞음.

- 앞서 확인한 것처럼 결정트리의 주요 단점은 훈련 데이터에 과대적합되는 경향이 있다는 것이다. R.F는 이 문제를 회피하는 방법이다.

- R.F는 기본적으로 조금씩 다른 여러 결정 트리의 묶음이다. R.F의 아이디어는 서로 다른 방향으로 과대적합된 트리를 많이 만들면 그 결과를 평균냄으로써 과대적합된 양을 줄일 수 있다는 것이다. 이렇게 하면 트리 모델의 예측 성능은 유지되면서 과대적합이 줄어드는 것이 수학적으로 증명 되었다.

- 랜덤 포레스트에서 트리를 랜덤하게 만드는 방법은 두 가지 이다.

- 트리를 만들 때 사용하는 데이터 포인트를 무작위로 선택하는 방법

- 분할 테스트에서 특성을 무작위로 선택하는 방법


- R.F 모델을 만들려면 생성할 트리의 개수를 정해야 한다. (RandomForest Regressor나 Classifier의 n_estimators 매개변수)

- 트리를 만들기 위해 부트스트랩 샘플을 생성 (n_samples개의 데이터 포인트 중에서 무작위로 데이터를 n_samples횟수만큼 반복 추출)

- 예를 들면 리스트 ['a','b','c','d']에서 부트스트랩 샘플을 만들면 ['b','d','c','d']가 될 수 있고 ['d','a','d','a']도 가능

- 이렇게 만든 데이터셋으로 결정 트리를 만듦. 이전의 결정 트리 알고리즘과 같이 각 노드에서 전체 특성을 대상으로 최선의 테스트를 찾는 것이 아니고, 알고리즘이 각 노드에서 후보 특성을 무작위로 선택한 후 이 후보들 중에서 최선의 테스트를 찾음. 몇 개의 특성을 고를지는 max_feature 매개변수로 조정할 수 있음. 후보 특성을 고르는 것은 매 노드마다 반복되므로 트리의 각 노드는 다른 후보 특성들을 사용하여 테스트를 만듦

- 부트스트랩 샘플링은 랜덤 포레스트의 트리가 조금씩 다른 데이터셋을 이용해 만들어지도록 함. 또 각 노드에서 특성의 일부만 사용하기 때문에 트리의 각 분기는 각기 다른 특성 부분 집합을 사용. 이 두 메커니즘이 합쳐져서 R.F의 모든 트리가 서도 달라지도록 만듦

- 이 방식에서 핵심 매개변수는 max_feature. max_feature를 n_feature로 설정하면 트리의 각 분기에서 모든 특성을 고려하므로 특성 선택에 무작위성이 들어가지 않음. max_features를 낮추면 R.F 트리들은 많이 달라지고 각 트리는 데이터에 맞추기 위해 깊이가 깊어짐

- R.F로 예측을 할 때는 먼저 알고리즘이 모델에 있는 모든 트리의 예측을 만듦. 회귀의 경우에는 이 예측들을 평균하여 최종 예측을 만듦. 분류의 경우에는 약한 투표 전략을 사용. 즉 각 알고리즘이 가능성 있는 출력 레이블의 확률을 제공함으로써 간접적인 예측을 함. 트리들이 예측한 확률을 평균내어 가장 높은 확률을 가진 클래스가 예측값이 된다.


- 매개변수: n_estimators(클수록 좋음. 더 많은 트리를 평균하면 과대적합을 줄여 안정적임), 

max_features(작은 max_feature는 과대적합을 줄여줌. 일반적으로 기본 값을 쓰는 것이 좋음), max_depth와 같은 가지치기 옵션 

- 장점: 성능이 매우 뛰어나고 매개변수 튜닝을 많이 하지 않아도 잘 작동하며 데이터의 스케일을 맞출 필요가 없음

단일 트리의 단점을 보완하고 장점은 그대로 가지고 있음. 만약 의사 결정 과정을 간소하게 표현해야 한다면 단일 트리를 사용 가능

- 단점: 텍스트 데이터 같이 매우 차원이 높고, 희소한 데이터에는 잘 작동하지 않음. 이런 데이터에는 선형 모델이 더 적합.

또한, 선형 모델보다 많은 메모리를 사용하며 휸련과 예측이 느림.


- 데이터 셋: from sklearn.datasets import make_moons, from sklearn.datasets import load_breast_cancer

- 라이브러리

- library: from sklearn.ensemble import RandomForestClassifier



6) Gradient Boosting Decision Tree: 랜덤 포레스트보다 조금 더 성능이 좋음. 랜덤 포레스트보다 학습은 느리나,

예측은 빠르고, 메모리를 조금 사용. 랜덤포레스트보다 매개변수 튜닝 많이 필요

- 그래디언트 부스팅 회귀 트리는 여러 개의 결정 트리를 묶어 강력한 모델을 만드는 또 다른 앙상블 방법 (이름만 회귀, 분류도 함)

- 랜덤 포레스트와 달리 그래디언트 부스팅은 이전 트리의 오차를 보완하는 방식으로 순차적으로 트리를 만듦

- 기본적으로 그래디언트 부스팅은 무작위성이 없음. 대신 강력한 사전 가지치기가 사용됨

- 그래디언트 부스팅은 보통 하나에서 다섯 정도의 깊지 않은 트리를 사용하기 때문에 메모리를 적게 사용하고 예측도 빠름

- 기본적인 아이디어는 얕은 트리 같은 간단한 모델을 많이 연결하는 것. 각각의 트리는 데이터의 일부에 대해서만 예측을 잘 수행할 수 있어서 트리가 많이 추가 될수록 성능이 좋아짐

- 중요한 매개변수로는 이전 트리의 오차를 얼마나 강하게 보정할 것인지를 제어하는 learning_rate가 있음. 학습률이 크면  트리는 보정을 하기 때문에 복잡한 모델을 만듦, n_estimators 값을 키우면 앙상블에 트리가 더 많이 추가되어 모델이 복잡도가 커지고 훈련 세트에서의 실수를 바로잡을 기회가 더 많아짐


- 매개변수: n_estimator, learning_rate

※ n_estimator가 클수록 좋은 랜덤 포레스트와는 달리, 그래디언트 부스팅에서는 크게하면 모델이 복잡해지고 과대적합될 가능성이 높아짐. 일반적인 관례는 가용한 시간과 메모리 한도에서 n_estimator를 맞추고 나서 적절한 learning_rate를 찾음

중요한 또 다른 매개변수는 각 트리의 복잡도를 낮추는 max_depth(또는 max_leaf_nodes)인데, 통상 그래디언트 부스팅 모델에서는 max_depth를 매우 작게 설정하며 트리의 깊이가 5보다 깊어지지 않게 한다.

- 장점: 다른 트리 기반 모델처럼 특성의 스케일을 조정하지 않아도 되고, 이진 특성이 연속적인 특성에서도 잘 동작함

- 단점: 매개변수를 잘 조정해야 한다는 것과 훈련시간이 김. 희소한 고차원 데이터에는 잘 작동하지 않음


- 데이터 셋: from sklearn.datasets import load_breast_cancer

- 라이브러리

- library: from sklearn.ensemble import GradientBoostingClassifier



7) Support Vector Machine: 비슷한 의미의 특성으로 이뤄진 중간 규모 데이터셋에 잘 맞음. 데이터 스케일 조정필요. 매개변수에 민감

- 커널 서포트 벡터 머신은 입력 데이터에서 단순한 초평면으로 정의되지 않는 더 복잡한 모델을 만들 수 있도록 확장

- 서포터벡터의 이론은 이 책에서는 별로 다루지 않았음.

- 기본적으로 커널, 서포트 벡터, 마진, hard/soft margin, 비선형 decision boundary 등의 내용은 wiki에서 보는 것이 좋다고 판단됨


- 매개변수: 규제 매개변수 C, 어떤 커널을 사용할지와 각 커널에 따른 매개변수

- 장점: 데이터의 특성이 몇 개 안 되더라도 복잡한 결정 경계를 만들 수 있음. 

- 단점: 저차원, 고차원의 데이터에 모두 잘 작동하지만 샘플이 많을 때는 잘 맞지 않음..

또 하나의 단점은 데이터 전처리와 매개변수 설정에 신경을 많이 써야됨. 분석하기도 어려움


근데 다른 책들이나, 요새 논문들을 보면 SVM을 많이 사용하는 데, 이 책의 저자는 SVM을 그닥 높이 평가하지 않는다는 느낌이 들었음..



8) 신경망: 특별히 대용량 데이터셋에서 매우 복잡한 모델을 만들 수 있음. 매개변수 선택과 데이터 스케일에 민감. 학습이 오래 걸림

- MLP(MultiLayer Perceptrons)는 여러 단계를 거쳐 결정을 만들어내는 선형 모델의 일반화된 모습습

- SVM과 마찬가지로, 은닉층, feed-forward, ReLU, tanh 등 wiki에서 보는 것이 더 좋을 것 같음. 내용을 너무 많이 함축시켜놓음음

- 어차피 김성훈 교수님의 딥러닝의 경우 모두를 위한 딥러닝이나 응교수님의 강의를 들을거니깐...?


- 매개변수: 신경망에서 가장 중요한 매개변수는 은닉층의 개수와 각 은닉층의 유닛수이다. 처음에는 한 개 또는 두 개의 은닉층으로 시작해서 늘려가야 된다. 각 은닉층의 유닛 수는 보통 입력 특성의 수와 비슷하게 설정하지만 수천 초중반을 넘는 일은 거의 없다.

신경망의 매개변수를 조정하는 일반적인 방법은 먼저 충분히 과대적합되어서 문제를 해결할만한 큰 모델을 만듦. 그런 다음 훈련데이터가 충분히 학습될 수 있다고 생각 될 때 신경망 구조를 줄이거나 규제 강화를 위해 alpha값을 증가시켜 일반화 성능을 향상시킴


- 장점: 대량의 데이터에 내재된 정보를 잡아내고 매우 복잡한 모델을 만들 수 있음. 충분한 연산 시간과 데이터를 주고 매개변수를 세심하게 조정하면 신경망은 (분류와 회귀 문제에 모두) 종종 다른 머신러닝 알고리즘을 뛰어넘는 성능을 냄

- 단점: 학습이 오래 걸림. 또한 전처리에 주의해야함.

반응형

현재 기준(2017년 4월 17일) 아나콘다 설치 시 파이썬이 3.6으로 기본 설치되어 

윈도우 사용자 기준으로  pip으로 tensorflow가 설치가 안되는 일이 발생한다. 

리눅스나 mac에서는 repository 지정해놓는 글을 본 것 같은데 윈도우는 못찾아서...


(Could not find a version that satisfies the requirement tensorflow (from version: ))


뭐 물론 파이썬3.6에서 3.5 환경에 맞게 바꿔주거나 하는 방법도 있겠다만, 아나콘다 설치 시 3.6을 디폴트로 설치가 되었기때문에 이래 저래 환경 변수 바꿔주는게 번거로울 수 있음


아래 URL에 접속하면 이전버전의 설치가 가능하다.

뭐 패치가 되겠지만, 이전버전이 필요할 수도 있기 때문에 기록~


개인적으로 3.5 추천

https://repo.continuum.io/archive/.winzip/

32비트 유저들은 위에거 다운받으면됨ㅋ


https://docs.continuum.io/anaconda/oldpkglists  //지원하는 버전의 패키지 설치 시 참고


설치 후 파이썬 버전을 확인하면 3.5로 설치된 것을 확인할 수 있다.


원래 우분투 사용할 때 apt-get update가 습관화 되어있는지 pip 도 업그레이드 한번 해주자~~


콘다 설정

>conda create -n tensorflow python=<python version>


텐서플로우를 활성화 시켜주는 것은 아래와 같다.

>activate tensorflow


3.6 때와 달리 설치가 잘되는 것을 확인할 수 있다~


파이썬 눌러주고  tensorflow 임포트 시켜주면 잘 되는 것을 확인할 수 있다.




정정!

왜 ipython이나 spyder에서 텐서플로우를 임포트 시킬 때 에러가 나는 것을 확인해봄

생각해보니 python3 이상은 pip3 아니던가


잘됨ㅋ

반응형

그림 발췌

https://blogs.msdn.microsoft.com/bigdatasupport/2015/09/14/understanding-sparks-sparkconf-sparkcontext-sqlcontext-and-hivecontext/

Cluster에서 운영

- 분산 모드에서 스파크는 하나의 Driver Program과 여러 Worker Node, Master/Slave 구조를 가진다.

DriverWorker NodeExecutor와 통신하는데, Driver는 자신만의 자바 프로세스에서 돌아가며, Executor 또한 독립된 자바 프로세스다.

- 하나의 Spark ApplicationCluster Manager라고 불리는 외부 서비스를 사용하여 여러 개의 머신에서 실행 된다.



- Driver: DriverMain Method가 실행되는 프로세스로, SparkContext를 생성하고 RDD를 만들고, TransformationAction을 실행하는 사용자 코드를 실행하는 프로세스

1) 사용자 프로그램을 Task로 변환

2) Executor에서 Task들의 Scheduling


- Executor: Spark Task를 실행하는 작업 프로세스. Spark application 실행 시 최초 한 번 실행되며, 대개 application이 끝날 때까지 계속 동작하지만, 오류로 죽더라도 Spark application은 계속 실행함

1) Application을 구성하는 작업들을 실행하여, 드라이버에 결과를 리턴

2) Executor 안에 존재하는 블록 매니저라는 서비스를 통해 사용자 프로그램에서 Cache하는 RDD를 저장하기 위한 메모리 저장소 제공


- Cluster Manager: Spark와 붙이거나 뗄 수 있는 컴포넌트. (Yarn, mesos, 내장 Manager 등 다양한 외부 매니저들 위에서 동라가게)


Program 실행하기

- 어떤 Cluster Manager를 사용하든 Spark는 사용자 프로그램을 Sparksubmit 할 수 있는  단일 스크립트인 Spark-submit을 제공

$ ./bin/spark-submit <script.py>  //localSpark program 실행

$ ./bin/spark-submit --master spark://host  :7077 --executor-memory 10g <script.py>

--master flag는 접속할 cluster의 주소를 지정해주는데, spark:// URLSpark의 단독 모드를 사용한 cluster 의미


- Spark-submit –master flag

1) spark://host:port: spark 단독 클러스터의 지정 포트 접속 (default: 7077)

2) memos://host:port: mesos cluster에 지정 포트 접속 (default: 5050)

3) yarn: yarn cluster 접속 (hadoop directory -> HADOOP_CONF_DIR 환경 변수 설정 필요)

4) local: 로컬 모드에서 싱글 코어로 실행

5) local[N]: N개코어로 로컬모드에서 실행

6) local[*]: 로컬모드에서 머신이 가지고 있는 만큼의 코어로 실행


- executor-memory <MEM>: executor 당 메모리 할당


- 자세한 내용은 spark-submit --help  참고

반응형

'기타 > 분산 컴퓨팅' 카테고리의 다른 글

Spark Accumulator  (0) 2017.04.07
Spark Data 불러오기/저장하기  (0) 2017.04.07
SparkContext, Reduce/Group By Key  (0) 2017.04.07
Spark Pair RDD 개념  (0) 2017.04.07
Spark RDD 개념 및 예제  (0) 2017.04.07

+ Recent posts