#2-6 KNN 군집화 알고리즘 사용하기 (질병 정보 분류하기) - 파이썬, pandas, sklearn

목차

    2017. 8. 29. 20:52

    빅데이터는 21세기 원유라고도 불리며, 데이터 분석 및 활용에 대해서 많은 사람들이 관심을 갖고 연구하고 있습니다. 하지만 데이터 분석, 모델링 등을 배워 보려고 해도책으로 보고 강의 듣는 것으로는 와 닿지 않는 것이 사실입니다. 

    그래서 저는 경마를 통해 데이터 분석을 공부함으로써 재미도 느끼고(베팅동 하고) 자기 계발도 하는 1석 2조의 효과를 보고자 합니다. 이 곳에서는 그렇게 공부한 내용들을 포스팅 하고 있습니다.
    (참조: 경마로 코딩 교육 배우기)

    오늘은 KNN 군집화 알고리즘을 사용해서 경주마들에게 생기는 질병을 그룹핑 해보고자 합니다.


    제목

    (출처: http://pythonhosted.org)



    추천포스트



    렛츠런파크 싸이트에는 말들에게 발생한 질병 및 치료에 대한 데이터가 적재되어 있습니다.

    이 정보를 활용하면 예측을 더 정확하게 할 수 있을 거라는 생각이 듭니다.

    하지만, 질병의 종류도 다양하고 그 내용을 알기도 어려울 뿐만 아니라 분류하는 것도 어렵습니다.

    검색을 해서 일부 질병들을 일일이 하나씩 분류할 수는 있지만, 결과도 생각보다 좋지 않을 뿐만 아니라 

    활용하지 못하는 정보다 많았습니다.


    그래서 군집화 알고리즘을 통해 군집을 만들어 보도록 하겠습니다.

    KNN 알고리즘은 비지도 학습 방법의 하나로 분류하고 싶은 군집의 갯수를 지정해 주면

    임의로 시작점을 설정하고 그 점과 가까이 있는 점들을 각각의 군집에 포함시키는 알고리즘입니다.



    저는 5개의 군집으로 분류를 해 보고자 합니다.


    자세한 내용을 알고자 sklearn 패키지의 홈페이지에 들어가 보았습니다. 

    K-means를 포함한 다양한 비지도 군집 알고리즘에 대해서 나와 있는데요. 9개나 되네요. 

    (링크: sklearn패키지의 clustering에 관한 설명)



    자세한 내용은 나중에 알아보는 것으로 하고, 일단 실행부터 해 보게 씁니다.


    먼저 데이터를 불러오겠습니다. 전체 데이터를 하면 너무 많을 것 같아 최근 3개월로 자르고 진행하도록 하겠습니다.

    실제 모델에 반영할 때도 최근 3개월 질병 데이터만 반영하려고 합니다.


    # coding=utf-8

    import sqlite3
    import pandas as pd
    from sklearn import cluster

    if __name__ == "__main__":

    con = sqlite3.connect("./data/race.db")
    cur = con.cursor()
    query = cur.execute("SELECT * From cure")
    cols = [column[0] for column in query.description]
    cure = pd.DataFrame.from_records(data=query.fetchall(), columns=cols)
    con.close()

    #최근 3개월
    cure_1 =cure[cure["진료일자"]>20170500]
    cure_1 = cure_1.reset_index(drop=True)



    현재 데이터는 렛츠런파크 싸이트에 있는 정보를 크롤링한 것이기 때문에, 한 행에 말 한마리에 대한 질병이 중복해서 들어가 있 습니다. 아래와 같이 말이죠.



           horse_no loc_idx      진료병원      진료일자   진료장소                   질병명

    0         38050     seo   닥터임동물병원  20170502  마방 진료            물리치료(쇽웨이브)

    1         36536     seo  서울부속동물병원  20170506   None        양후낭축농증, 기타(입원)

    2         36536     seo  서울부속동물병원  20170505  원내 진료        양후낭축농증, 기타(입원)

    3         36536     seo  서울부속동물병원  20170504  원내 진료        양후낭축농증, 기타(입)

    .......




    그래서 두 번째 행에 있는 데이터 같은 경우에 말번호 36536에 양후낭축농증, 기타(입원) 이라고 되어 있는 것을 분리해야 합니다. "36536, 양후낭축농증" / "36536, 기타(입원)" 이런 식으로 말이죠. 그래서 아래와 같이 데이터를 comma(,) 로 분리하고 각각을 데이터 프레임에 추가하여 새로운 dataframe을 만들었습니다.


    df2 = pd.DataFrame()
    t = cure_1[["horse_no","질병명"]]
    t = t.reset_index(drop=True)

    for x in range(len(t)):
    a = t.loc[x,"질병명"].split(",")
    if len(a) == 1:
    r = pd.DataFrame({"horse_no":t.loc[x,"horse_no"],"질병명": a}, index=[0])
    df2 = pd.concat([df2, r])
    else:
    for y in range(len(a)):
    r = pd.DataFrame({"horse_no":t.loc[x,"horse_no"], "질병명": a[y]}, index=[0])
    df2 = pd.concat([df2, r])



    아래와 같이 말번호 하나에 질병정보 하나만 들어가도록 분리가 되었습니다.


        horse_no           질병명

    0      38050    물리치료(쇽웨이브)

    0      36536        양후낭축농증

    0      36536        기타(입원)

    0      36536        양후낭축농증

    0      36536        기타(입원)

    0      36536        양후낭축농증

    0      36536        기타(입원)

    0      36536        양후낭축농증




    그리고 지금은 질병명이 행으로 주욱 입력되어 있는데 각각의 질병명을 column으로 옮기고, 해당하는 질병에 걸렸는지

    여부를 0과 1로 표현하려고 합니다. 그렇게 변형해야 kmeans알고리즘을 돌릴 수 있기 때문입니다.


    df2["c"]=1
    table = pd.pivot_table(df2, index="horse_no", columns="질병명", values="c", aggfunc="count")
    table = table.fillna(0)
    table = table.reset_index(drop=True)



    pandas의 pivot table문을 이용해서 변경을 했습니다. "c"라는 변수에 1이라는 값을 넣어놓고, 행에 말번호를 칼럼에 질병병을 넣어놓고, 값에는 "c"의 갯수를 세서 값을 넣었습니다. 해당 병에 걸리지 않은 말의 경우, 해당 값이 null로 들어가기 때문에 fillna 구문을 이용하여 0으로 값을 입력하였습니다.


    질병명 각막염 감기 건인대성형술 교돌상 근육통 기타(입원) 나사고정술 낭치 담마진 마체검사 ... \ 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 2 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ...



    실제 알고리즘을 적용하는 것은 너무도 간단한데요. 2줄이면 되네요. 여기까지는 쉽지만, 각각의 알고리즘의 장단점을 알아 적합한 알고리즘을 적용하고 결과를 해석해서 정교화하는 부분은 어려울 것 같다는 생각이 듭니다. 일단 해 보는 것은 참 쉽습니다. 5개의 군집으로 만들 것이고, fit구문을 이용해서 적용하였습니다. 결과가 dataframe형태가 아니기 때문에, out이라는 dataframe으로 바꾸고, 원래 dataframe과 결합하였습니다.


    k_means = cluster.KMeans(n_clusters=5)
    k_means.fit(table)
    out=pd.DataFrame(k_means.labels_)

    table=pd.concat([table,out],1)



    아래와 같이 군집이 생성되었습니다.


    감기 교돌상 근육통 낭치 담마진 폐렴 피부염 피부병 cluster 마체검사 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1 0.0 1 0.0 0.0 0.0 0.0 0.0 0.0 6.0 0.0 2 0.0 2 0.0 3.0 0.0 0.0 0.0 0.0 0.0 0.0 4 0.0 3 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 2 0.0 4 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 2 1.0 5 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1 0.0

    .......



    하지만, 어떻게 군집을 나눴는지에 대해서는 알기가 어렵습니다.


    그래서 다음에는 군집을 어떻게 나누었는지 파악하기 위해, 의사결정나무(decision tree)를 적용해 보았는데요. 자세한 내용은 아래 링크를 참조해주세요.

    (참조: decision tree 알고리즘 사용하기)