소프트웨어 개발/Python

파이썬으로 간단한 실제 분류기 만들기

늘근이 2015. 11. 28. 23:57

본 글은 Building Machine Learning Systems with Python을 보고 흐름을 따라갔습니다.

 

 

Iris 는 심심할만 하면 나오는 예제로, 꽃받침 길이, 꽃받침 너비, 꽃잎 길이, 꽃잎 너비로 꽃의 형태학적 모양을 표현한 자료이다. 꽃을 구분하는것은 인간이 구분할수 있기 때문에 구분되었던게 당연하고 이를 컴퓨터가 잘 구분하여야 하는 문제이다.

일단 Iris라는 데이터는 이렇게 생겼다.

 

iris 데이터 추출

from sklearn.datasets import load_iris

data = load_iris()

 

위와같이 데이터를 불러온 후에,

 

데이터마다 구분해주기

featureNames = data.feature_names
features = data.data
targetNames = data.target_names
target = data.target

 

위의 명령어로 구분할수 있는데, 여기서 targetNames에는 구분해야 하는 꽃의 이름이 있다. SETOSA / VERSICOLOR / VIRGINICA 세가지와 같다.

이 세가지의 꽃은 각각의 Feature값들을 가지고 있는데, 이는 꽃받침 길이(sepal length), 꽃받침 너비(sepal width), 꽃잎 길이 (petal length), 꽃잎 너비 (petal width) 와 같다.

features 에는 이 길이와 너비들의 정보가 array형식으로 들어있으며

target에는 실제로 이 수치를 가지고 있는놈이 무슨 꽃인가라는 정보를 정수형으로 가지고 있다. 즉, 0 - SETOSA / 1 - VERSICOLOR / 2 - VIRGINICA 이렇게 구분되어있다.

 

이제 마지막으로 plot을 그려볼수 있는데

for t in range(3) :
    if t == 0 :
      color = 'r'
      marker = '>'
   elif t == 1 :
      color = 'g'
      marker = 'o'
   elif t == 2 :
      color = 'b'
      marker = 'x'
  
   plt.scatter(features[target == t,0],
                  features[target == t,1],
                  marker = marker,
                  c = color)

plt.show() 

 

타겟을 계속해서 바꿔주면서 한 그래프에 산점도를 뿌리게끔하고 있는데, 사실은 0열 1열 말고도 2열 3열에도 데이터가 있기 때문에 위의 방식을 통하면 꽃받침 길이 - 꽃받침 너비 밖에 보지 못한다.

 

 

 

 

이제 실제로 이 산점도를 가지고 분류를 해볼수 있는데, 빨간색은 딱봐도 쉽게 구분할수 있을것같은 생각이 드는데 파란색과 초록색은 여러가지가 섞여있게 보인다.

일단, 꽃잎의 길이가지고 그냥 냅다 구분을 해볼수가 있다. 일단 setosa는 곷잎의 길이가 굉장히 작다.

아래와같이, 0,1,2로 구분하지 말고 레이블을 하나하나 붙여줄수 있다.

labels = targetNames[target]

그리고 다음과 같이 꽃잎 길이가 2열에(세번째) 있으므로 그 데이터를 빼온다.

plength = features[:,2]

그리고 setosa인 놈들의 꽃잎길이중에 제일 큰것이 몇인가 까본다.

isSetosa = (labels == 'setosa')

maxSetosa = plength[isSetosa].max()

minNoSetosa = plength[~isSetosa].max()

 

까보면 setosa는 아무리 커봤자 1.9의 값을 가지며 다른것들은 3.0의 값을 가진다

maxSetosa
Out[14]: 1.8999999999999999

minNoSetosa
Out[15]: 3.0

 

그렇다면 경계선은 적당히 꽃받침 크기를 2.5로 하면 setosa는 죄다 구분이 된다. 끝이다. 다만, 현실적으로는 완벽히 나눠지는것은 없다. 


이제 setosa는 그냥 구분 하나로 나눠지니 재미가 없다. 이건 제외하고 데이터셋을 만든다.


features = features[~isSetosa]

labels = labels[~isSetosa]


isVirginica = (labels == 'virginica')


다음은 vriginica를 구분하는알고리즘을 짜본다. (책에 있는 코드는 쓰잘데기 없는게 많아서 수정했다.)


생각해볼수 있는 알고리즘은 일단 꽃받침 길이, 너비, 꽃잎 길이, 너비 총 네가지 중 하나를 선택해서 제일 구분을 잘할수 있는 기준을 잡는것이다. 따라서 크게는 이 기준으로 루프를 돌면 된다.


for i in range(4) :

vec_numbers = features[:,i]


루프는 총 네번돌며 한 열씩 튀어나온다. 꽃받침 길이, 너비, 꽃잎 길이, 너비 가 벡터로 전환이 되면서 계산이 된다. 이 튀어나온 벡터 안에 있는 값들을 하나씩 꺼내서 어떤 값을 가지는지 보고 그 기준으로 한번 그 벡터에 있는 값을 쭉 한번 나눠보고 이를 실제 labeled된 벡터와 일치하는지 한번 비교해볼수 있다. 

즉 현재 돌고있는 스칼라값보다 큰지 벡터를 (True, False, False..) 가지게 한다음에

이를 Virginica 에 대한 boolean 벡터와 비교하는거다 (True, False, Ture..) 

비교를 해보니 첫번째와 두번째는 맞았으니 그 특정한 값을 기준으로 데이터를 나눌 경우에는 정확도가 66%일것이다. 이런 과정을 모든 값에 대해 다 해보면 된다. 


#모든 feature를 경계선을 삼아 정확도를 계산 알고리즘을 짠다.

guess = 0


for i in range(4) :

vec_numbers = features[:,i]

#vector에 있는 숫자 하나하나가 기준값으로 적용됨.

for thresh in vec_numbers :

arr_predict = (vec_numbers > thresh)

float_accuracy = (arr_predict == isVirginica).mean()

if float_accuracy > guess :

guess = float_accuracy

best_i = i

best_thresh = thresh

print(guess)

print(best_i)

print(best_thresh)

Numpy는 강력하지만 그만큼 행렬인지 벡터인지 스칼라값인지 좀 알기가 힘들기 때문에 타입을 표시했다. 다 쓰고보니 arr_predict는 vec_predict가 맞겠으나 귀찮아서 고치지 않겠다.


튜닝의 기운이 물씬 풍기지만, 어쨌든 그렇다 치고 한번 실행시켜 본다.




꽃잎너비를 기준으로 데이터를 나눴으며, 경계값은 1.6이다. 그리고 최종 예측기의 확률은 94%이다. 그럴듯하지 않은가?




 

 

_png 관련해서 DLL 모듈을 찾을수없습니다 에러가 날경우

콘솔에서

$ conda install anaconda

$ conda create -n working python=3 anaconda

명령어로 초기화 하고 각 모듈에 대해 업데이트 받는다.

 

위의 경우로 해결이 안될 경우는 다음과 같은 경우일수 있다.

C:\Users\Admin\Anaconda2\Library\bin 을 PATH에 등록한다.

(파이썬이 2와 3가 동시에 설치되어있을경우 PATH가 각각 다르게 잡혀있는 경우가 있다. 업데이트를 해도 소용이 없으니 PATH를 한가지 버전으로 통일한다.)

 

마지막으로는 싹 밀어버리고 재설치

1) 삭제 .conda-env-post-link.bat in C:\Users\Admin\Anaconda2\Scripts
2) 콘솔에서 conda update python (this also installed conda-env).
3) 콘솔에서 conda update --all
4) 콘솔에서 "conda install chaco" then ran with no errors