본문 바로가기

데이터 분석 학습

[혼자공부하는머신러닝+딥러닝] Ch.01 나의 첫 머신러닝 리뷰 / K-최근접 이웃 모델

본 포스팅은 저를 포함한 책을 구입한 분들의 학습 정리를 위해 쓰여졌습니다. 

 

 

 

혼자 공부하는 머신러닝 딥러닝(유튜브 강의도 있다!)

혼자 공부하는 머신러닝 딥러닝은 데이터 분석 분야의 꽃인 머신러닝과 딥러닝이 대체 뭐에 쓰는 물건인지 알고 싶어하는 사람들을 위한 입문서다. 

수학과 통계 지식이 전무한 사람들도 실 예시를 통해서 충분히 이해할 수 있을만큼 쉽게 잘 쓰여진 책이다.

 

시중에서 이만한 책을 고르기 쉽지 않을듯하다. 두꺼운 책이긴 하지만 길고 긴 데이터 공부의 여정에 비하면 새발의 피에 불과하니 한번 끝까지 달려보자. 참고로 여기에선 각 코드에 대한 자세한 설명은 하지 않는다. 파이썬 코드에 익숙하지 않은 사람은 파이썬 기본서와 파이썬 활용 데이터분석 기본서를 먼저 학습하고 오는 것을 추천한다.

 

Ch.01 나의 첫 머신러닝

 

이 단원에서는 인공지능, 머신러닝, 딥러닝에 대한 정의(Ch.01-1)와 코랩, 주피터 노트북 사용법(Ch.01-2), 간단한 분류 문제(Ch.01-3)로 구성되어 있다. 특히 앞 두 부분은 실습과정이 아니라 매우 매우 기초적인 정의와 이론을 다룬다. 이 챕터는 간단한 키워드 정리 형태로 공부하는 것이 효과적이다. 코랩의 사용법에 대해서 자세히 다루지만 본 포스팅에서는 다루지 않고 넘어간다

 

역시 사용법은 제조사에서 만드는 걸 한번 천천히 읽어보는게 최고다.

https://colab.research.google.com/ 

 

Google Colaboratory

 

colab.research.google.com

 

Ch.01-1 인공지능과 머신러닝, 딥러닝

Keyword

1. 인공지능(Artificial intelligence): 사람처럼 학습하고 추론할 수 있는 지능을 가진 컴퓨터 시스템

인공지능의 종류

일반인공지능(Artificial general intelligence) or 강인공지능(strong AI)

- 사람과 구분하기 어려운 지능을 가진 컴퓨터 시스템

약인공지능(Weak intelligence):

- 특정 분야에서 사람의 일을 도와주는 보조 역할을 하는 컴퓨터 시스템. 음성 비서, 자율주행 자동차, 기계 번역 등이 대표적인 예

 

2. 머신러닝(Machine Learning):  자동으로 데이터에서 규칙을 학습하는 알고리즘을 연구하는 분야. 인공지능의 하위 분야 중에서 지능을 구현하기 위한 소프트웨어를 담당하는 핵심 분야. 

머신러닝 라이브러리 '사이킷런(scikit-learn)'

파이썬 API를 사용하는 사이킷런 하이브러리는 대표적인 오픈소스 머신러닝 라이브러리로 누구나 머신러닝 알고리즘을 무료로 손쉽게 제품에 적용시킬 수 있다.

 

 

 

3. 딥러닝(Deep Learning): 머신러닝 알고리즘 중에 인공 신경망(Artificial neural netwrok)을 기반으로 한 방법을 통칭하여 딥러닝이라 함. 

구글의 오픈소스 딥러닝 라이브러리 '텐서플로'

페이스북의 오프소스 딥러닝 라이브러리 '파이토치'

 

Ch.01-2 코랩과 주피터 노트북

Keyword

1. 코랩(Colab): 구글에서 제공하는 클라우드 기반의 주피터 노트북 개발환경. 무료로 파이썬 프로그램을 테스트하고 저장할 수 있으며 머신러닝 프로그램도 만들 수 있다. 클라우드는 구글 드라이브를 이용한다.

노트북(Notebook)
코랩으로 작성된 파일을 지칭하는 말

셀(Cell)
코드 또는 텍스트의 덩어리, 코랩에서 실행할 수 있는 최소단위이며 노트북은 보통 여러 개의 코드 셀과 텍스트 셀로 이루어진다.

텍스트 셀(Text cell)

HTML, 마크다운(Markdown)을 혼용해서 사용 가능하며 코드에 대한 설명을 주로 담는다

코드 셀(Code cell)
코드를 작성하는 셀

 

2. 주피터 노트북(Jupyter Notebook): 코랩은 대화식 프로그래밍 환경인 주피터(Jupyter)를 커스터마이징 한 것으로 주피터 프로젝트의 대표 제품이 바로 주피터 노트북이다.

 

* 자세한 얘기는 이전 게시글에 담아놓았으니 궁금하면 참고하자.

2022.03.23 - [데이터 분석 학습] - [모두의 데이터분석 With 파이썬] Unit.02 리뷰 / 주피터, 코랩

 

[모두의 데이터분석 With 파이썬] Unit.02 리뷰 / 주피터, 코랩

Unit.01 리뷰 보러가기 Unit.02 서울의 기온데이터 분석하기 이번 유닛은 실제 코드를 입력하고 실행할 IDE 환경에 대해 학습한다. 일단, 아나콘다와 크롬을 설치했다면 주피터 노트북(Jupyter Notebook)

yunjuniverse.tistory.com

 

Ch.01-3 마켓과 머신러닝 

여기서부터는 예시를 통한 머신러닝 입문이 시작된다. 캐글Kaggle에서 제공하는 생선데이터를 이용해 생선의 종류를 분류하는 문제를 푼다. 해당 데이터 셋은 여기서 받을 수 있다.

https://www.kaggle.com/datasets/aungpyaeap/fish-market

 

Fish market

Database of common fish species for fish market

www.kaggle.com

 

* 머신러닝에서 여러 종류(class) 중 하나를 구별해내는 문제를 분류(classification)라고 부른다. 만약 2개의 클래스 중 하나를 고르는 문제라면 이는, 이진 분류(binary classification)라고 한다. 명심해야할 점은 머신러닝에서의 클래스는 파이썬의 클래스와 다르다는 것이다.

 

도미와 빙어를 구분하는 이진 분류 문제를 풀어보자. 가장 먼저 생각해 볼 수 있는 풀이법은 무게와 길이를 가지고 분류하는 것이다. 

 

bream의 길이와 무게를 가져왔다.

 

* http://bit.ly/bream_list 에서 복붙하자

도미(Bream)

 

#생선의 길이
bream_length = [25.4, 26.3, 26.5, 29.0, 29.0, 29.7, 29.7, 30.0, 30.0, 30.7, 31.0, 31.0, 
                31.5, 32.0, 32.0, 32.0, 33.0, 33.0, 33.5, 33.5, 34.0, 34.0, 34.5, 35.0, 
                35.0, 35.0, 35.0, 36.0, 36.0, 37.0, 38.5, 38.5, 39.5, 41.0, 41.0]
#생선의 무게
bream_weight = [242.0, 290.0, 340.0, 363.0, 430.0, 450.0, 500.0, 390.0, 450.0, 500.0, 475.0, 500.0, 
                500.0, 340.0, 600.0, 600.0, 700.0, 700.0, 610.0, 650.0, 575.0, 685.0, 620.0, 680.0, 
                700.0, 725.0, 720.0, 714.0, 850.0, 1000.0, 920.0, 955.0, 925.0, 975.0, 950.0]

 

단위는 cm와 g으로 보인다. 이런 무게와 길이의 특징을 데이터 분야에서는 특성(feature)이라고 부른다.

이 두 특성을 데카르트 좌표계에 올려보면 시각적으로 표현이 가능하다. x축은 길이, y축은 무게로 지정해준다. 이렇게 만들어질 그래프를 산점도(scatter plot)이라 부른다. 

 

파이썬에서 과학 계산용 그래프를 그리는 패키지는 맷플롯립(Matplotlib)이다. 이 패키지를 임포트해서 산점도를 그리는 scatter() 함수를 사용해본다

 

import matplotlib.pyplot as plt #matplotlib의 pyplot함수를 plt로 줄여서 사용

plt.scatter(bream_length, bream_weight)
plt.xlabel('length') #x축은 길이
plt.ylabel('weight') #y축은 무게
plt.show()

 

대충 보니 무게와 길이가 정비례관계를 가지는 선형적(linear) 특성을 지닌다. 우리는 무게와 길이가 서로 상관관계를 가진다는 것을 발견했다!

 

smelt 녀석도 보면

빙어(smelt), 영국식 영어에선 smell의 과거형과같다....

 

smelt_length = [9.8, 10.5, 10.6, 11.0, 11.2, 11.3, 11.8, 11.8, 12.0, 12.2, 12.4, 13.0, 14.3, 15.0]
smelt_weight = [6.7, 7.5, 7.0, 9.7, 9.8, 8.7, 10.0, 9.9, 9.8, 12.2, 13.4, 12.2, 19.7, 19.9]
plt.scatter(bream_length, bream_weight)
plt.scatter(smelt_length, smelt_weight)
plt.xlabel('length') #x축은 길이
plt.ylabel('weight') #y축은 무게
plt.show()

빙어는 노란색, 도미는 파란색

 

빙어는 도미에 비해 길이와 무게가 매우 작고 비례도도 낮다. 아무래도 작은 녀석이다보니 큰 차이가 없는 것 같다. 데이터를 모두 확인했으니, 두 데이터를 스스로 분류하는 첫 머신러닝 프로그램을 만든다.

 

'K-최근접 이웃(K-Nearest Neighbors)'이라는 알고리즘을 사용해 도미와 빙어 데이터를 구분한다.

 

일단 두 리스트를 합쳐준다.

 

#K-Nearest Neighbors(K-최근접 이웃) 알고리즘을 사용
length = bream_length + smelt_length
weight = bream_weight + smelt_weight

 

여기서 앞서 배웠던 머신러닝 패키지인 사이킷런(scikit-learn)을 사용하려면 각 특성의 리스트를 세로 방향으로 늘어뜨린 2차원 리스트를 만들어야 한다.

zip()함수와 리스트 내포list comprehension 구문을 사용해 리스트를 만들어보자.

 

#Scikit-learn(사이킷런) 사용
#사이킷런을 사용하려면 2차원 리스트로 전환 -> 파이썬의 zip() 함수와 리스트 내포(list comprehension) 구문을 사용
#zip() 함수: 나열된 리스트에서 원소를 하나씩 꺼내 주는 함수
#for 반복문: 하나씩 꺼낸 데이터에 동일한 작업을 계속 반복하는 함수, zip() 함수로 length와 weight 리스트에서 원소를 하나씩 꺼내어 l과 w에 할당
fish_data = [[l, w] for l, w in zip(length, weight)]
#[l,w]가 하나의 원소로 구성된 리스트 제작

 

for 구문을 이용해 l, w에 해당하는 값을 각각 길이와 무게에 넣어 줬다.

print()함수를 이용해 [길이, 무게] 형태로 잘 넣어졌는지 확인해보면

 

print(fish_data)

결과값: [[25.4, 242.0], [26.3, 290.0], [26.5, 340.0], [29.0, 363.0],.........

 

이쁘게 담겨있다. 이런 리스트를 2차원 리스트 혹은 리스트의 리스트라고 한다.

이제 컴퓨터가 이렇게 담겨 있는 값을 보고 분류를 해야하는데 컴퓨터는 문자를 이해못한다! 따라서 각각의 분류 값을 자연어로 바꾸어준다. 도미는 1로 빙어는 0으로 생각하면 1은 35번 등장하고 0은 14번이 등장할 것이다. 그리고 앞서 도미를 앞 쪽에 담고 빙어를 뒤에 붙여서 리스트에 담았으므로 정답 데이터를 이와 동일하게 만들어 준다.

 

#도미를 1로 두고 빙어를 0으로 둠
#첫 번째 35개 원소는 '도미(1)', 이후 14개 원소는 '빙어(0)'
#보통 찾는 대상을 축적 가능한 수 '1'로 지정하고 그 외에는 '0'으로 놓음
fish_target = [1]*35+[0]*14

 

정답 데이터도 만들었으므로 이제 알고리즘을 구현한 클래스인 KNeighborsClassifier를 불러와본다. 이렇게 머신러닝 알고리즘을 구현한 프로그램을 모델(model)이라고 한다.

 

#scikit_learn 임포트
from sklearn.neighbors import KNeighborsClassifier

 

가져온 클래스의 객체를 먼저 정의해준다. 이렇게 해야 다음부터 클래스 이름을 길게 사용할 필요가 없다

 

#임포트한 KNeighborsClassifier() 클래스의 객체를 먼저 정의
kn = KNeighborsClassifier()

 

이 객체에 fish_data와 fish_target을 전달하여 도미를 찾기 위한 기준을 학습시킨다. 이런 과정을 머신러닝에서는 훈련(training)이라 한다. 사이킷런에서는 fit() 메서드가 이런 역할을 한다.

 

#training
kn.fit(fish_data, fish_target)

 

어이없게도 이 한 줄로 훈련이 끝났다..... 사이킷런에서 모델을 평가하는 메서드는 score() 메서드다.

 

# model accuracy
kn.score(fish_data, fish_target)

결과값: 1.0

 

1.0.... 다 맞았다는 소리다. 정확도(accuracy)가 100%라고 표현한다.

 

그럼 새로운 데이터가 들어와도 정확히 구분해낼까? 임의의 값을 넣어 어떻게 예측을 하는지 확인해보자. 예측을 위한 메서드는 predict()이다. 이렇게 새로운 데이터를 넣을 때 아까와 같이 리스트의 리스트를 전달해야한다.

 

# predict
kn.predict([[30,600]])
#1로 출력되어 도미인 것으로 확인
#KNeighborsClassifier()는 결국 비슷한 x, y값을 가진 원소끼리 묶어 같은 것으로 분류하는 알고리즘. 단점으로는 데이터가 많은 경우 사용이 어려움(메모리할당, 직선거리 계산)

결과값: array([1])

 

array()안에 1이라는 값으로 나오는 것을 보니 학습모델은 저 데이터 값은 bream으로 측정했다. 저 값이 도미 데이터와 가깝다는 의미다. 

 

 

K-최근접 이웃 알고리즘은 아주 간단한 방식으로 분류하는 모델이지만, 직교좌표상의 거리를 측정하는 특징 때문에 데이터가 많은 경우 사용하기 어렵다. 데이터가 크기 때문에 메모리가 많이 필요하고, 직선거리를 계산하는데도 시간이 많이 필요하기 때문이다.

 

실제로 훈련한 데이터를 뜯어보면 훈련되어 있는게 아무것도 없다. fit()메서드에 전달한 데이터를 그저 모두 저장해 놓았다가 새로운 데이터가 등장하면 가장 가까운 데이터를 참고하여 분류할 뿐이다.

 

print(kn._fit_X)
print(kn._y)
#직접 확인해보자

 

참고로 K-최근접 이웃 알고리즘은 기본적으로 거리가 가까운 5개의 값을 참고하는데, 원한다면 n_neighbors 매개변수로 기준을 바꿔 줄 수 있다.

 

#K-최근접이웃모델은 가장 가까이 있는 데이터 몇개를 활용하여 예측을 하는 모델임. 몇 개의 데이터를 참고할지도 정할 수 있음 n_neighbors 매개변수로 변경가능
#n_neighbors = N   , N이 데이터의 수
kn49 = KNeighborsClassifier(n_neighbors=49)
kn49.fit(fish_data, fish_target)
kn49.score(fish_data, fish_target)

결과값: 0.7142857142857143

 

더 많은 데이터를 참고했는데 더 낮은 결과가 나왔다. 우리가 49개 데이터 전체를 참고했기 때문에 모델은 저 모든 데이터 값이 다수를 차지하는 bream이라고 학습을 했고, 결국 빙어 데이터를 넣어도 도미로 인식하기 때문이다! 이와 같이 더 많은 학습 데이터를 참고하고 학습한다는 것이 좋은 결과를 무조건 내지 않는다. 앞으로의 머신러닝 모델을 다룰 때도 이런 점을 고려해야한다.

 

 

그럼 가장 쉬웠던 1장은 끝!

 

Keyword

캐글(Kaggle): 2010년에 설립된 전세계에서 가장 큰 머신러닝 경연 대회 사이트. 

패키지(Package): 기능을 구현할 함수를 특정 기능별로 묶어 둔 것.

특성(feature): 데이터의 구분되는 값, 데이터를 표현하는 하나의 성질

산점도(scatter plot): 직교 좌표계(도표)를 이용해 좌표상의 점들을 표시함으로써 두 개 변수 간의 관계를 나타내는 그래프 방법

메서드(Method): 패키지 내 명령을 실행하는 함수

모델(Model): 머신러닝 알고리즘을 구현한 프로그램 ex) K-최근접 이웃 모델

훈련(training): 타겟 데이터 값을 찾기 위한 기준 학습

정확도(Accuracy):  예측 성공 확률

리스트의 리스트(List of list): 리스트를 리스트로 감싼 형태로, 머신러닝에서 계산을 위해 사용되는 방법이다. 이를 2차원 리스트 (two-dimension list)라고도 한다.

 

matplotlib

scatter('x축값', 'y축값'): 산점도를 그리는 맷플롯립 함수

 

scikit-learn

KNeighborsClassifier(): K-최근접이웃모델, 어떤 데이터에 대한 답을 구할 때 다른 데이터를 보고 다수를 차지하는 것을 정답으로 사용한다. 즉, 주위의 데이터로 현재의 데이터를 판단하는 것이다.

    n_neighbors=: 이웃의 개수 지정

    p=: 거리를 재는 방법 지정, 1일 경우 맨허튼 거리, 2일 경우 유클리디안 거리를 사용한다. 기본값은 2

    n_jobs=: 매개변수로 사용할 CPU코어 수 지정, -1로 지저하면 모든 CPU코어 사용, 속도를 높일 때 사용

fit(): 훈련을 위한 메서드

score(): 모델 평가를 위한 메서드

predict(): 새로운 데이터 예측을 위한 메서드