파알못 파이썬: 9. 초간단 머신러닝

Table of Content

파이썬을 공부한 내용을 정리한 글입니다. 파알못이라 이상하거나 틀린 내용이 있을 수 있습니다…

강아지와 고양이를 분석 및 구분하는 프로그램을 만든다고 가정해봅시다. 기존 프로그래밍 방식으로 이 프로그램을 구현한다면 엄청나게 복잡해집니다. 골격, 곡선 등을 따져야 하는 경우의 수도 방대하고 흑백 사진일 경우 제대로 작동하지 않을 수 있습니다.

그러나 머신 러닝을 활용하면 기존 방식에 비해 간단하게 구현할 수 있습니다. 강아지와 고양이의 사진을 수천 장씩 주고 이 입력 데이터에서 학습된 패턴을 찾는다면 어느정도 정확성이 구현된 프로그램을 만들 수 있을 것입니다. 물론 입력 데이터가 많아질 수록 더 정확해지겠지요.

여기서는 머신 러닝 프로젝트 환경 구축에 Anaconda와 Jupyter를, 2차원 데이터(엑셀 등) 분석에 주로 사용하는 pandas를, 기계 학습을 위해 scikit-learn를 사용해 보겠습니다.

프로젝트 환경 구축

머신 러닝 프로젝트는 데이터를 자주 검사해야 하기 때문에 VSCode 및 터미널 환경에서 진행하기엔 적절치 않습니다. 여기서는 Anaconda와 Jupyter를 사용합니다. https://www.anaconda.com/distribution 에서 Anaconda를 다운로드 받아 설치합니다.

설치 후 Anaconda를 실행한 후 Jupyter Notebook을 실행합니다. 실행하면 웹 브라우저에 홈 디렉토리에 위치한 디렉토리 및 파일 리스트가 보입니다.

Desktop 디렉토리에 Python 3용 Notebook을 만들어보겠습니다. Desktop 디렉토리로 이동하여 우측의 New 리스트를 클릭한 후 Notebook: Python 3를 클릭합니다. Notebook을 사용하면 작성된 파이썬 코드를 한 줄 씩 실행할 수 있습니다.

제목인 Untitled를 HelloWorld로 변경하면 데스크톱 화면에 HelloWorld.ipynb 파일이 생성됩니다. 다시 Notebook으로 돌아와서 print("Hello World") 파이썬 코드를 입력한 뒤 Run 버튼을 클릭하면 실행 결과가 나타납니다.

In [ ]: print('hello world!')

데이터 셋 가져오기

https://www.keggle.com 에서 데이터 세트를 가져옵니다. Keggle은 Jupyter Notebook 환경 및 데이터 분석을 위한 다양한 데이터를 제공하는 사이트입니다. 회원 가입이 필요합니다.

여기서는 Video Game Sales라는 데이터셋을 가져오겠습니다. Keggle에서 video game sales라고 검색한 후 최상위에 검색되는 결과에 들어가 Download 버튼을 클릭하여 csv 파일을 다운로드 받습니다.

다운받은 csv 파일을 Jupyter Notebook 파일(HelloWorld.ipynb)와 같은 경로로 이동시킵니다. 그 다음 Jupyter Notebook에서 다음 파이썬 코드를 입력한 후 실행시키면 csv 파일 내용이 출력됩니다.

In [ ]: import pandas as pd
        pd.read_csv('vgsales.csv')
Rank Name Platform Year Genre Publisher NA_Sales EU_Sales JP_Sales Other_Sales Global_Sales
0 1 Wii Sports Wii 2006 Sports Nintendo 41.49 29.02 3.77 8.46 82.74
1 2 Super Mario Bros. NES 1985 Platform Nintendo 29.08 3.58 6.81 0.77 40.24
2 3 Mario Kart Wii Wii 2008 Racing Nintendo 15.85 12.88 3.79 3.31 35.82
3 4 Wii Sports Resort Wii 2009 Sports Nintendo 15.75 11.01 3.28 2.96 33
4 5 Pokemon Red/Pokemon Blue GB 1996 Role-Playing Nintendo 11.27 8.89 10.22 1 31.37
16593 16596 Woody Woodpecker in Crazy Castle 5 GBA 2002 Platform Kemco 0.01 0 0 0 0.01
16594 16597 Men in Black II: Alien Escape GC 2003 Shooter Infogrames 0.01 0 0 0 0.01
16595 16598 SCORE International Baja 1000: The Official Game PS2 2008 Racing Activision 0 0 0 0 0.01
16596 16599 Know How 2 DS 2010 Puzzle 7G//AMES 0 0.01 0 0 0.01
16597 16600 Spirits & Spells GBA 2003 Platform Wanadoo 0.01 0 0 0 0.01
16598 rows x 11 columns

shape 속성을 호출하면 csv 파일의 레코드 수와 열의 개수를 보여줍니다.

In [ ]: import pandas as pd
        df = pd.read_csv('vgsales.csv')
        df.shape
Out [ ]: (16598, 11)  # 16598개의 레코드와 11개의 열을 갖는 csv 파일

describe() 함수를 호출하면 각 열의 총 개수, 평균, 표준편차, 최대 및 최소값 등을 보여줍니다.

In [ ]: import pandas as pd
        df = pd.read_csv('vgsales.csv')
        df.describe()
Rank Year NA_Sales EU_Sales JP_Sales Other_Sales Global_Sales
count 16598 16327 16598 16598 16598 16598 16598
mean 8300.605254 2006.406443 0.264667 0.146652 0.077782 0.048063 0.537441
std 4791.853933 5.828981 0.816683 0.505351 0.309291 0.188588 1.555028
min 1 1980 0 0 0 0 0.01
25% 4151.25 2003 0 0 0 0 0.06
50% 8300.5 2007 0.08 0.02 0 0.01 0.17
75% 12449.75 2010 0.24 0.11 0.04 0.04 0.47
max 16600 2020 41.49 29.02 10.22 10.57 82.74

values 속성을 호출하면 배열을 반환합니다.

In [ ]: import pandas as pd
        df = pd.read_csv('vgsales.csv')
        df.values
Out [ ]: array([[1, 'Wii Sports', 'Wii', ..., 3.77, 8.46, 82.74],
           [2, 'Super Mario Bros.', 'NES', ..., 6.81, 0.77, 40.24],
           [3, 'Mario Kart Wii', 'Wii', ..., 3.79, 3.31, 35.82],
           ...,
           [16598, 'SCORE International Baja 1000: The Official Game', 'PS2',
            ..., 0.0, 0.0, 0.01],
           [16599, 'Know How 2', 'DS', ..., 0.0, 0.0, 0.01],
           [16600, 'Spirits & Spells', 'GBA', ..., 0.0, 0.0, 0.01]], dtype=object)

Jupyter 단축키

Jupyter 입력 칸 밖에서 h 키를 누르면 단축키 목록이 뜹니다. 주요 단축키는 다음과 같습니다.

  • a: 새로운 입력(In) 칸을 이전 칸에 삽입
  • b: 새로운 입력(In) 칸을 다음 칸에 삽입
  • d: 칸 삭제
  • command + /: 주석
  • shift + tab: 함수의 툴팁 보기

대충 머신러닝 실습

아래 music.csv 파일을 다운로드 받은 후 Jupyter에서 music.csv 파일을 가져옵니다.

이 파일엔 다음과 같이 나이, 성별, 음악장르 데이터가 저장되어 있습니다. gender 값이 0이면 여성을, 1이면 남성을 가리킵니다.

age gender genre
20 1 HipHop
23 1 HipHop
25 1 HipHop
26 1 Jazz
29 1 Jazz
30 1 Jazz
31 1 Classical
33 1 Classical
37 1 Classical
20 0 Dance
21 0 Dance
25 0 Dance
26 0 Acoustic
27 0 Acoustic
30 0 Acoustic
31 0 Classical
34 0 Classical
35 0 Classical

이 데이터엔 20, 23, 25세의 남성이 선호하는 음악은 HipHop, 20, 21, 25세의 여성이 선호하는 음액은 Dance로 명시되어 있습니다. 그렇다면 21세의 남성이 선호하는 음악과 22세의 여성이 선호하는 음악은 무엇일까요? 이를 예측하기 위한 머신러닝 실습을 해보겠습니다.

데이터 가져오기

In [ ]: import pandas as pd
        music_data = pd.read_csv('music.csv')
        music_data

데이터 준비

수힉시간에 자주 봤을 법한 함수 f(x) = y를 생각해봅시다. 이 함수는 x를 입력받아 y라는 값을 산출합니다. 머신러닝에서도 이와 비슷하게 데이터를 준비해야 합니다.

우리는 나이와 성별에 따라 선호하는 음악장르가 무엇인지 예측하려 합니다. 즉 입력값 x에 해당하는 것은 나이와 성별, 출력값 y에 해당하는 것은 음악장르라고 볼 수 있습니다.

따라서 입력 데이터와 출력 레이블을 다음과 같이 명시해야 합니다.

in [ ]: import pandas as pd
        from sklearn.tree import DecisionTreeClassifier

        music_data = pd.read_csv('music.csv')
        # genre 컬럼을 제외한 입력 데이터 셋 생성(주로 대문자)
        X = music_data.drop(columns=['genre'])
        # 출력 레이블 생성(주로 소문자)
        y = music_data['genre'] 

학습과 예측

머신러닝 알고리즘을 사용하여 모델을 작성합니다.

in [ ]: import pandas as pd
        from sklearn.tree import DecisionTreeClassifier

        music_data = pd.read_csv('music.csv')
        # genre 컬럼을 제외한 데이터 셋 생성(주로 대문자)
        X = music_data.drop(columns=['genre']) 
        # 출력 레이블 생성(주로 소문자)
        y = music_data['genre'] 

        model = DecisionTreeClassifier()
        # 입력 데이터 셋과 출력 레이블 지정
        model.fit(X, y)
        # 21세 남성과 22세 여성의 선호음악 예측
        predictions = model.predict([ [21, 1], [22, 0] ])
        predictions
out [ ]: array(['HipHop', 'Dance'], dtype=object)

정확도 계산

정확도를 계산하기 위해 데이터의 일부를 테스트용으로 분할한 후 테스트 용 데이터로 계산한 결과와 그렇지 않은 데이터로 계산한 결과를 비교합니다.

in [ ]: import pandas as pd
        from sklearn.tree import DecisionTreeClassifier
        from sklearn.model_selection import train_test_split
        from sklearn.metrics import accuracy_score

        music_data = pd.read_csv('music.csv')
        # genre 컬럼을 제외한 데이터 셋 생성(주로 대문자)
        X = music_data.drop(columns=['genre']) 
        # 출력 레이블 생성(주로 소문자)
        y = music_data['genre']

        # 테스트 용 데이터를 20%로 지정
        # train_test_split() 함수는 튜플을 반환
        X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

        model = DecisionTreeClassifier()
        # 테스트 용 데이터 셋과 그렇지 않은 데이터 지정
        model.fit(X_train, y_train)
        # 테스트 용 데이터 셋을 입력하여 예측
        predictions = model.predict(X_test)
        # 예측치 비교
        score = accuracy_score(y_test, predictions)
        score

위의 코드를 실행하면 정확도가 0과 1사이의 값으로 나옵니다. 그런데 test_size 값을 높일수록 정확도는 대체로 떨어지게 됩니다. 그 이유는 우리가 실습 중인 데이터는 매우 적기 때문입니다.

이것이 머신러닝의 핵심입니다. 모델에 제공하는 데이터의 개수가 방대할수록, 그 데이터가 정확할수록 더 나은 결과를 얻을 수 있습니다.

머신러닝 모델 파일로 저장하기

학습을 끝낸 모델을 파일로 저장한 후 추후에 불러들어 재사용하는 방법에 대해 알아보겠습니다.

pip3 install joblib 명령어로 joblib 패키지를 설치한 후 joblib.dump() 함수를 사용하여 모델을 파일로 저장합니다.

in [ ]: import pandas as pd
        from sklearn.tree import DecisionTreeClassifier
        import joblib

        music_data = pd.read_csv('music.csv')
        # genre 컬럼을 제외한 데이터 셋 생성(주로 대문자)
        X = music_data.drop(columns=['genre']) 
        # 출력 레이블 생성(주로 소문자)
        y = music_data['genre'] 

        model = DecisionTreeClassifier()
        model.fit(X, y) # 테스트 용 데이터 셋과 그렇지 않은 데이터 지정
        joblib.dump(model, 'music-recommender.joblib') # 모델 저장

파일로 저장된 모듈을 불러오려면 joblib.load() 함수를 사용합니다.

in [ ]: import pandas as pd
        from sklearn.tree import DecisionTreeClassifier
        import joblib

        joblib.load('music-recommender.joblib') # 모델 불러오기

의사결정트리 시각화

그래프 저장용 텍스트 파일인 dot 파일로 저장합니다.

in [ ]: import pandas as pd
        from sklearn.tree import DecisionTreeClassifier
        from sklearn import tree

        music_data = pd.read_csv('music.csv')
        X = music_data.drop(columns=['genre'])
        y = music_data['genre']

        model = DecisionTreeClassifier()
        model.fit(X, y)

        tree.export_graphviz(model, 
                     out_file='music-recommender.dot',
                     feature_names=['age', 'gender'],
                     class_names=sorted(y.unique()), # 클래스 이름을 고유한 genre로 설정 및 정렬,
                     label='all', # 모든 노드에 레이블 지정,
                     rounded=True, # 각 노드를 모서리가 둥글게 그림,
                     filled=True) # 각 노드를 색상으로 채움

“파알못 파이썬: 9. 초간단 머신러닝”의 하나의 댓글

댓글 남기기