본문 바로가기

Study/AI

머신러닝 공부 #2

04. 머신러닝

  • 4-1. 머신러닝이란?
  • 4-2. 머신러닝 첫걸음
  • 4-3. 이미지 내부의 문자 인식
  • 4-4. 외국어 문장 판별하기
  • 4-5. 서포트 벡터 머신(SVM)
  • 4-6. 랜덤 포레스트
  • 4-7. 데이터를 검증하는 방법

 

머신러닝 첫걸음

머신러닝 프레임워크 scikit-learn

scikit-learn은 다양한 분류기를 지원하며, 머신러닝의 결과를 검증하는 기능도 가지고 있습니다.

또한 분류, 회귀, 클러스터링, 차원 축소처럼 머신러닝에서 자주 사용되는 다양한 알고리즘을 지원합니다.

또한 머신러닝을 바로 테스트해볼 수 있게 샘플 데이터도 제공합니다.

 

scikit-learn은 pip 명령어를 사용해 패키지를 설치할 수 있음

pip3 install -U scikit-learn scipy matplotlib scikit-image

 

데이터를 읽어 들이고 분할할 때 편리하게 사용할 수 있는 Pandas도 설치합니다.

pip install pandas

 

XOR 연산 학습해보기

논리 연산 가운데 배타적 논리합(XOR)이라는 연산

 

from sklearn import svm

# XOR의 계산 결과 데이터 (*1)
xor_data = [
    [0,0,0],
    [0,1,1],
    [1,0,1],
    [1,1,0]
]

# 학습을 위해 데이터와 레이블 분리하기 (*2)
data = []
label = []
for row in xor_data:
    p = row[0]
    q = row[1]
    r = row[2]
    data.append([p, q])
    label.append(r)
    
# 데이터 학습시키기 (*3)
clf = svm.SVC()
clf.fit(data, label)

# 데이터 예측하기 (*4)
pre = clf.predict(data)
print("예측 결과: ", pre)

# 결과 확인하기 (*5)
ok = 0;
total = 0;

for idx, answer in enumerate(label):
    p = pre[idx]
    if p == answer: ok += 1
    total += 1

print("정답률: ", ok, "/" , total, "=", ok/total)

 

프로그램 *2 에서는 입력을 "학습시키기 위한 데이터 변수"와 "정답 레이블 변수"로 나눕니다.

이렇게 나누는 이유는 scikit-learn의 머신러닝을 수행할 때 사용하는 fit() 메서드의 매개변수를 맞추기 위함입니다.

 

프로그램 *3 에서는 SVM이라는 알고리즘을 사용해 머신러닝을 수행합니다.

SVM 객체를 만들고, fit() 메서드를 사용해 데이터를 학습시킵니다.

fit() 메서드는 첫 번째 매개변수로 학습할 데이터 배열을, 두 번째 매개변수로 레이블 배열을 전달합니다.

 

프로그램 *4 에서는 학습한 결과를 기반으로 데이터를 예측합니다.

predict() 메서드에 예측하고 싶은 데이터 배열을 전달하면 데이터 수만큼 예측 결과를 리턴해줍니다.

 

프로그램 *5 에서는 예측 결과가 정답과 맞는지 확인합니다.

for 반복문을 사용해 하나하나의 예측 결과가 맞는지 확인하고, 정답률을 계산했습니다.

 

(1) 학습 기계에 데이터를 학습시킨다 - fit() 메서드

(2) 데이터를 넣어 예측시킨다 - predict() 메서드

 

 

프레임워크로 프로그램 간단하게 작성하기

scikit-learn에는 데이터와 레이블을 나누고, 정답률을 간단하게 계산해주는 기능이 있습니다.

 

import pandas as pd
from sklearn import svm, metrics


# XOR 연산
xor_input = [
    [0,0,0],
    [0,1,1],
    [1,0,1],
    [1,1,0]
]

# 입력을 학습 전용 데이터와 테스트 전용 데이터로 분류하기 *1
xor_df = pd.DataFrame(xor_input)
xor_data = xor_df.loc[:,0:1] # 데이터
xor_label = xor_df.loc[:,2] # 레이블

# 데이터 학습과 예측하기 *2
clf = svm.SVC()
clf.fit(xor_data, xor_label)
pre = clf.predict(xor_data)

# 정답률 구하기 *3
ac_score = metrics.accuracy_score(xor_label, pre)
print("정답률 = ", ac_score)

정답률 = 1.0

 

프로그램이 굉장히 간단해졌는데, 프로그램의 *1 에서는 입력된 데이터를 학습 데이터와 레이블로 나눕니다.

딱 3줄밖에 되지 않습니다. 이는 Pandas 모듈의 DataFrame 기능을 사용했기 때문입니다.

 

*2 에서는 학습시키고, 예측합니다.

성공률을 구하는 *3도 한 줄로 줄었습니다. metrics.accuracy_score() 함수를 이용하면 정답률을 이처럼 쉽게 구할 수 있습니다.

이때 매개변수는 실제 답과 예측 결과 배열을 전달합니다.

 

붓꽃의 품종 분류하기

머신러닝을 사용해 꽃잎과 꽃받침의 크기를 기반으로 분류해봅시다.

 

붓꽃 데이터 구하기

iris.csv

iris.csv
0.00MB

'Iris-setosa', 'Iris-versicolor', 'Iris-virgincia' 라는 3가지 종류입니다.또한 각각의 붓꽃에 대해 "SepalLength(꽃받침의 길이)", "SepalWidth(꽃받침의 폭)", "PetalLength(꽃잎의 길이)", "PetalWidth(꽃잎의 너비)" 정보가 기록돼 있습니다.

 

머신러닝으로 붓꽃 품종 분류하기

프로그램의 목표는 꽃잎과 꽃받침의 길이와 폭을 기반으로 붓꽃의 품종을 분류하는 것입니다.CSV 파일에는 150개의 데이터가 들어 있는데, 100개는 학습을 위해 사용하고, 50개는 테스트를 위해 사용합니다.

 

from sklearn import svm, metrics
import random, re

#  붓꽃의 CSV 데이터 읽어 들이기 *1
csv = []

with open('iris.csv', 'r', encoding='utf-8') as fp:
    # 한 줄씩 읽어 들이기
    for line in fp:
        line = line.strip() # 줄바꿈 제거
        cols = line.split(',') # 쉼표로 자르기
        # 문자열 데이터를 숫자로 변환하기
        fn = lambda n : float(n) if re.match(r'^[0-9\.]+$', n) else n
        cols = list(map(fn, cols))
        csv.append(cols)
        
 # 가장 앞 줄의 헤더 제거
del csv[0]

# 데이터 셔플하기(섞기) * 2
random.shuffle(csv)

# 학습 전용 데이터와 테스트 전용 데이터 분할하기 (2:1 비율) *3
total_len = len(csv)
train_len = int(total_len * 2 / 3)
train_data = []
train_label = []
test_data = []
test_label = []

for i in range(total_len):
    data = csv[i][0:4]
    label = csv[i][4]
    
    if i < train_len:
        train_data.append(data)
        train_label.append(label)
    else:
        test_data.append(data)
        test_label.append(label)
 
 # 데이터를 학습시키고 예측하기 *4
clf = svm.SVC()
clf.fit(train_data, train_label)
pre = clf.predict(test_data)

# 정답률 구하기 * 5
ac_score = metrics.accuracy_score(test_label, pre)
print("정답률 = ", ac_score)

 

정규 표현식을 사용해 해당 셀의 내용이 숫자인지 확인하고, 숫자라면 float()을 사용해 실수로 변환합니다.

lambda로 익명 함수를 정의하고, 리스트에 처리를 적용하는 map() 함수를 사용해 리스트 내부의 모든 값을 변환합니다.

문자열에서 숫자로 변환하는 lambda에서는 삼항 연산자를 사용하고 있습니다.

 

[서식] 파이썬의 삼항 연산자(값) = (True 일때의 값) if (조건) else (False일 때의 값)

 

*2 에서는 random 모듈의 suffle()을 사용해 리스트를 셔플합니다.*3 에서는 150개의 데이터를 학습 전용 100개, 테스트 전용 50개로 분할합니다.

 

* 4에서는 이전과 마찬가지로 SVC 알고리즘을 사용해 데이터를 학습하고, 테스트 전용 데이터를 사용해 분류해봅시다.마지막으로 분류 결과를 기반으로 정답률을 구합니다.

 

훈련 전용 데이터와 전용 데이터로 분할하는 메서드

이전의 붓꽃 데이터를 학습할 때처럼 훈련 전용 데이터와 테스트 전용 데이터로 분할하는 것은 굉장히 귀찮은 작업입니다.

그래서 sckit-learn은 이러한 작업을 대신하는 메서드를 제공합니다.

model_selection 모듈의 train_test_split() 메서드입니다.

 

import pandas as pd
from sklearn import svm, metrics
from sklearn.model_selection import train_test_split

# 붓꽃의 CSV 데이터 읽어 들이기 *1
csv = pd.read_csv('iris.csv')

# 필요한 열 추출하기 *2
csv_data = csv[["sepal.length", "sepal.width", "petal.length", "petal.width"]]
csv_label = csv["variety"]

# 학습 전용 데이터와 테스트 전용 데이터로 나누기 *3
train_data, test_data, train_label, test_label = \
    train_test_split(csv_data, csv_label)
    
# 데이터를 학습시키고 예측하기 *4
clf = svm.SVC()
clf.fit(train_data, train_label)
pre = clf.predict(test_data)

# 정답률 구하기 *5
ac_score = metrics.accuracy_score(test_label, pre)
print(ac_score)

 

*1 에서는 Pandas를 사용해 CSV파일을 읽어 들입니다.* 2 에서는 CSV를 열 이름으로 분할합니다. 현재 CSV에는 가장 앞 행에 열 이름이 지정돼 있습니다.이 이름을 사용해 원하는 열을 분할하는 것입니다.

 

*3 에서는 train_test_split() 메서드를 사용해 훈련 전용 데이터와 학습 전용 데이터를 분할합니다.*4 에서는 학습과 예측을 수행하고 *5 에서는 정답률을 구합니다.

 

* train_test_split() 메서드

train_test_split(data, target, test_size=0.2, shuffle=True, stratify=target, random_state=34)

 

옵션 값 설명

  • test_size: 테스트 셋 구성의 비율을 나타냅니다. train_size의 옵션과 반대 관계에 있는 옵션 값이며, 주로 test_size를 지정해 줍니다.
    0.2는 전체 데이터 셋의 20%를 test (validation) 셋으로 지정하겠다는 의미입니다. 
    default 값은 0.25 입니다.
  • shuffle: default=True 입니다. split을 해주기 이전에 섞을건지 여부입니다. 보통은 default 값으로 놔둡니다.
  • stratify: default=None 입니다. classification을 다룰 때 매우 중요한 옵션값입니다.
    stratify 값을 target으로 지정해주면 각각의 class 비율(ratio)을 train / validation에 유지해 줍니다.
    (한 쪽에 쏠려서 분배되는 것을 방지합니다)
    만약 이 옵션을 지정해 주지 않고 classification 문제를 다룬다면, 성능의 차이가 많이 날 수 있습니다.
  • random_state: 세트를 섞을 때 해당 int 값을 보고 섞으며, 하이퍼 파라미터를 튜닝시 이 값을 고정해두고 튜닝해야 매번 데이터셋이 변경되는 것을 방지할 수 있습니다.