용's

[#2] Weka - 데이터 마이닝을 위한 Tool 본문

Computer Science/Graduate Project

[#2] Weka - 데이터 마이닝을 위한 Tool

TaeYOng's 2015. 7. 21. 00:00



지난 포스트에서 간단한 졸업과제 개요와 Bayes Net에 대해서 알아 보았다.


간단한 프로세스를 정리하면 다음과 같을 것이다.





스마트홈 내부의 IoT들과 사용자의 여러 상황들간의 인과관계를 파악한다


파악된 인과관계를 통하여 Bayesian Network를 설계한다


2번에서 얻은 Bayes Net을 이용하면, 주어진 Query에 대한 특정 상황의 확률을 구할 수 있을 것이다. 예를 들면 다음과 같은 상황을 스마트홈이 인지했다고 하자.


 Dining Room Light

Gas Range 

Toilet

Standing 

 On

 On

 Off

 Off




이럴 때 사용자가 Cooking일 확률을 Bayes Net을 통해 다음과 같이 구할 수 있다. 


P(Cooking | DiningRoomLight = On, GasRange = On, Toilet = Off, Standing = Off)


(위와 같은 확률은 각 노드의 CPT(Conditional Probability Table) 값을 통해 구할 수 있다)


각 상황에 따른 정확한 확률적인 추론을 하기 위해 학습(learning)을 시켜야 한다


학습을 위한 데이터가 필요한데, 실제 스마트홈을 시간단위로 측정할 수 없으므로 임의로 충분한 시뮬레이션 데이터를 구성한다




5번에서 더 많은 절차가 요구되지만 일단 여기까지 정리를 해보았다.


간단하게 말하는 Bayesian Network를 이용해서 학습을 해야 한다.


그리고 다음으로 고민해야 할 것이 어떤 프로그래밍 언어를 사용할 것인가 이다.


C++에서는 이와 같은 Machine Learning(Data Mining)을 위한 Library로서 

dlib라는 오픈 소스가 존재한다. 


나의 주 프로그래밍 언어는 C++이다. 

(사실은 내가 잘한다고 말할 수 있는 언어는 딱히 없었지만

최근 여럿 게임 회사 면접을 보면서 게임회사에 맞게 자연스럽게 C++로 선택하게...)


하지만 아무리 찾아도 dlib을 이용할 시, 제가 구성한 시뮬레이션 데이터를 통대로 

각 노드에 대한 CPT를 구해주는 예제 및 설명을 찾아 볼 수가 없었다...

그렇다고 내가 직접 각 노드에 대한 모든 CPT를 구하는 함수를 만든다 해도... 

일일이 다 카운트 해줘야할 뿐만 아니라, 

노드수가 꽤나 많기 때문에 비효율적으로 느껴졌다.


한 Node의 Parent Node가 3개만 있어도

 그 해당 Node의 CPT entry는 16개가 된다.

(해당 노드의 cardinality가 2라는 가정하에 16개이다. 

cardinality가 높을수록 CPT의 Entry는 훨씬 더 커진다)



서론이 굉장히 길었지만, 아무튼 내가 구성한 시뮬레이션 데이터를 토대로 CPT를 코딩을 통해 구해야하는데 dlib는 이러한 부분을 제공하지 않는 것으로 보였다. 


그래서 발견한 것이 Weka이다.





Weka는 간단하게 

'a collection of machine learning algorithms for data mining tasks'

(데이터 마이닝을 수행하기 위한 머신 러닝 알고리즘의 모임)

이라고 한다.


일단 제공하는 Tool로서는 Pre-Processing, Classification, Regression, Clustering, Association rules, 그리고 Visualization이라고 한다. 그리고 빅데이터를 적용시킬 수 있다고 되어 있다. 


자세한 내용은 http://www.cs.waikato.ac.nz/~ml/weka/ 에서 확인 및 다운로드 할 수 있다.




위 사진은 실행한 모습이다. 


참고로, 나는 이 포스팅을 통해 Bayesian Network를 다루는 부분만 진행할 예정이다.


위의 사진에서 'Explorer'를 선택하면 다음과 같은 사진의 화면이 실행된다.




일단 이 포스팅에서는 Weka에서 기본적으로 제공해주는 데이터로 

베이지안 네트워크를 사용해 보자.


위의 사진에서 'Open file...' 을 한 뒤에 

Weka가 설치된 폴더에서 data 폴더로 가면

(예를 들면, C:\Program Files\Weka-3-7\data) 

기본적으로 제공되는 여러 예제파일들이 있음을 볼 수 있다.


여러 예제 파일들 중에 weather.nominal.arff 파일을 열면 

인공지능 시간에 배웠던

 날씨에 따른 Play 여부를 결정짓는 예제를 볼 수 있다. 


weather.nominal.arff을 열면 다음과 같은 form임을 확인 할 수 있다.



@relation weather.symbolic


@attribute outlook {sunny, overcast, rainy}

@attribute temperature {hot, mild, cool}

@attribute humidity {high, normal}

@attribute windy {TRUE, FALSE}

@attribute play {yes, no}


@data

sunny,hot,high,FALSE,no

sunny,hot,high,TRUE,no

overcast,hot,high,FALSE,yes

rainy,mild,high,FALSE,yes

rainy,cool,normal,FALSE,yes

rainy,cool,normal,TRUE,no

overcast,cool,normal,TRUE,yes

sunny,mild,high,FALSE,no

sunny,cool,normal,FALSE,yes

rainy,mild,normal,FALSE,yes

sunny,mild,normal,TRUE,yes

overcast,mild,high,TRUE,yes

overcast,hot,normal,FALSE,yes

rainy,mild,high,TRUE,no




그리고 파일을 선택했을 시 Weka화면은 다음과 같다.



여기서 나는 Bayes Net을 이용할 것이므로 Classify 탭으로 이동해보면 다음과 같다.

(참고로 Bayes Net은 Classification에 속한다)



여기서 위의 사진의 Choose를 선택하고 아래의 사진 처럼 BayesNet을 선택해보자



BayesNet을 선택했다면 다른 옵션을 건드리지 말고 Start 버튼을 눌러보자.

그러면 아래의 사진과 같이 Start버튼 아래에 Result list에 결과가 하나 생성된다. 



Result list에 생긴 결과에 오른쪽 클릭하면 여러 옵션이 뜨는데, 그 중에서 Visualize Graph를 선택하면 아래의 사진 처럼 해당 데이터에 대한 Bayesian Network를 볼 수 있다. 




또한 각 노드를 클릭해보면 각 노드에 대한 CPT까지 확인해볼 수 있는데, 

위의 사진에서 예를 들면,

P(windy = true | play = true) 의 확률이 0.35 인 것을 알 수 있다. 

즉 내가 밖에 나가서 놀았을 때, 바람이 불었을 확률이 35%인 것이다. 

물론 Play가 Windy의 원인이 되는 노드는 아니지만, 다른 옵션을 건드리지 않고 기본 설정으로 Play를 가장 상단에 설정해두었으므로 위와 같은 결과가 나온 것이다. 


아무튼 또 다른 Weka의 강점으로는

이 네트워크에 대한 것을 xml 형식으로 저장까지 가능하다...

강력하다. 이거 때문에 Weka를 선택하게 된 것이다.

위의 네트워크를 xml형식으로 저장했을 시 다음과 같은 xml파일이 생성됨을 알 수 있다.




<?xml version="1.0"?> <!-- DTD for the XMLBIF 0.3 format --> <!DOCTYPE BIF [ <!ELEMENT BIF ( NETWORK )*> <!ATTLIST BIF VERSION CDATA #REQUIRED> <!ELEMENT NETWORK ( NAME, ( PROPERTY | VARIABLE | DEFINITION )* )> <!ELEMENT NAME (#PCDATA)> <!ELEMENT VARIABLE ( NAME, ( OUTCOME | PROPERTY )* ) > <!ATTLIST VARIABLE TYPE (nature|decision|utility) "nature"> <!ELEMENT OUTCOME (#PCDATA)> <!ELEMENT DEFINITION ( FOR | GIVEN | TABLE | PROPERTY )* > <!ELEMENT FOR (#PCDATA)> <!ELEMENT GIVEN (#PCDATA)> <!ELEMENT TABLE (#PCDATA)> <!ELEMENT PROPERTY (#PCDATA)> ]> <BIF VERSION="0.3"> <NETWORK> <NAME>weather.symbolic-weka.filters.unsupervised.attribute.ReplaceMissingValues</NAME> <VARIABLE TYPE="nature"> <NAME>outlook</NAME> <OUTCOME>sunny</OUTCOME> <OUTCOME>overcast</OUTCOME> <OUTCOME>rainy</OUTCOME> <PROPERTY>position = (0,90)</PROPERTY> </VARIABLE> <VARIABLE TYPE="nature"> <NAME>temperature</NAME> <OUTCOME>hot</OUTCOME> <OUTCOME>mild</OUTCOME> <OUTCOME>cool</OUTCOME> <PROPERTY>position = (79,90)</PROPERTY> </VARIABLE> <VARIABLE TYPE="nature"> <NAME>humidity</NAME> <OUTCOME>high</OUTCOME> <OUTCOME>normal</OUTCOME> <PROPERTY>position = (158,90)</PROPERTY> </VARIABLE> <VARIABLE TYPE="nature"> <NAME>windy</NAME> <OUTCOME>TRUE</OUTCOME> <OUTCOME>FALSE</OUTCOME> <PROPERTY>position = (237,90)</PROPERTY> </VARIABLE> <VARIABLE TYPE="nature"> <NAME>play</NAME> <OUTCOME>yes</OUTCOME> <OUTCOME>no</OUTCOME> <PROPERTY>position = (79,0)</PROPERTY> </VARIABLE> <DEFINITION> <FOR>outlook</FOR> <GIVEN>play</GIVEN> <TABLE> 0.23809523809523808 0.42857142857142855 0.3333333333333333 0.5384615384615384 0.07692307692307693 0.38461538461538464 </TABLE> </DEFINITION> <DEFINITION> <FOR>temperature</FOR> <GIVEN>play</GIVEN> <TABLE> 0.23809523809523808 0.42857142857142855 0.3333333333333333 0.38461538461538464 0.38461538461538464 0.23076923076923078 </TABLE> </DEFINITION> <DEFINITION> <FOR>humidity</FOR> <GIVEN>play</GIVEN> <TABLE> 0.35 0.65 0.75 0.25 </TABLE> </DEFINITION> <DEFINITION> <FOR>windy</FOR> <GIVEN>play</GIVEN> <TABLE> 0.35 0.65 0.5833333333333334 0.4166666666666667 </TABLE> </DEFINITION> <DEFINITION> <FOR>play</FOR> <TABLE> 0.6333333333333333 0.36666666666666664 </TABLE> </DEFINITION> </NETWORK> </BIF>




xml에 보면 정확하게 CPT에 대한 확률 값까지 포함하고 있음을 알 수 있다.


그리해서... 사실은 weka를 이용해서 Bayesian Network를 만들고 xml 파일을 생성하여 

시뮬레이션 데이터들에 대한 각 노드의 CPT값을 파싱하여 가져올 생각이었다. 


그리하여 찾아보니 weka가 기본적으로 API를 제공해주긴 한다. 

하지만 기본적으로 Java로 말이다. 

왜냐면, Weka가 Java로 만들어졌으니까.


C++ API도 얼핏 비슷하게 만들어 누군가 제공하는 듯하지만, 

너무 코드가 어려워보이고 이게 Weka API인지도 모르겠더라...

(기본적으로 C++에서 파싱 자체가 조금 복잡하다 보니...)


그런데 'python-weka-wrapper라는 것이 있었다. 

Weka를 Python으로 이용할 수 있는 라이브러리 한다... 

대박... 안그래도 Python과 같은 스크립트 언어를 하나 배워보고 싶었고, 또 Python을 이용한다면 굉장히 코드가 쉽게 빨리 구현될 거 같은 느낌이 들어 무조건 이걸 이용해야겠다는 생각을 했다. 


물론 Weka가 기본적으로 JVM에서 돌아가기 때문에 python에서 이용하기 전에 

이것저것 많이 깔아줘야했지만... 

이미 다 설치하고 예제까지 테스트 해보았다... 


python-weka-wrapper 에 대해서는 


http://pythonhosted.org/python-weka-wrapper/ 에서 확인할 수 있다. 

아주 자세히 잘 나와 있다.




다음 포스팅에서는 Using Weka from within Python에 대해 다루고자 한다.





Comments