파이썬/ai

[Ai, python]KNN - Linear Regression3

hojung 2022. 4. 11.
728x90
반응형

1. Linear Regression

 

앞선 포스팅까지 행했던 것은 classification 즉 분류였다. 

미리 몇 개의 집합을 설정해두고 데이터들에 대한 집합 정답지를 알려준 뒤 새로 들어온 데이터가 어떤 집합과 가까운 지 거리를 파악하고 가장 거리가 가까운 집합으로 분류를 하는 작업이었다. 

 

하지만 이제 할 것은 Regression 즉 회귀이다. Regression이란 어떠한 데이터들을 학습시켜 새로운 데이터가 들어왔을  데이터에 대한 어떠한 값을 예측하는 문제를 말한다. 예를 들어 최근 10년간의 서울의 집 값 데이터를 모델에게 학습시킨 후 앞으로 1년 뒤의 서울의 집 값은 어떻게 되겠는가?라는 질문을 던졌을 때 예측치를 내놓는 것이 Regression이다. 

Regression 문제를 수행함에 있어 서울의 집 값의 경우 영향을 끼치는 다양한 요소가 있을 수 있다. 하지만 오늘 보고자 하는 것은 Linear Regression즉 선형 회귀이다. 수학에서 선형 그래프를 생각해보면 변수는 하나에 해당한다. 즉 이 그래프에 영향을 미치는 요인은 단 한가지라는 것이다. 

따라서 오늘은 농어의 길이를 통해 농어의 무게를 예측하는 knn regression 모델을 학습시키는 수업을 복습해 볼 것이다. 


2. Linear Regression 구현

1. 데이터 준비 

import matplotlib.pyplot as plt
import numpy as np

perch_length = np.array(
    [8.4, 13.7, 15.0, 16.2, 17.4, 18.0, 18.7, 19.0, 19.6, 20.0,
     21.0, 21.0, 21.0, 21.3, 22.0, 22.0, 22.0, 22.0, 22.0, 22.5,
     22.5, 22.7, 23.0, 23.5, 24.0, 24.0, 24.6, 25.0, 25.6, 26.5,
     27.3, 27.5, 27.5, 27.5, 28.0, 28.7, 30.0, 32.8, 34.5, 35.0,
     36.5, 36.0, 37.0, 37.0, 39.0, 39.0, 39.0, 40.0, 40.0, 40.0,
     40.0, 42.0, 43.0, 43.0, 43.5, 44.0]
)
perch_weight = np.array(
    [5.9, 32.0, 40.0, 51.5, 70.0, 100.0, 78.0, 80.0, 85.0, 85.0,
     110.0, 115.0, 125.0, 130.0, 120.0, 120.0, 130.0, 135.0, 110.0,
     130.0, 150.0, 145.0, 150.0, 170.0, 225.0, 145.0, 188.0, 180.0,
     197.0, 218.0, 300.0, 260.0, 265.0, 250.0, 250.0, 300.0, 320.0,
     514.0, 556.0, 840.0, 685.0, 700.0, 700.0, 690.0, 900.0, 650.0,
     820.0, 850.0, 900.0, 1015.0, 820.0, 1100.0, 1000.0, 1100.0,
     1000.0, 1000.0]
)

우선 준비해 둔 데이터 셋을 입력해주겠다. 위는 농어의 길이 밑은 농어의 무게에 해당하는 데이터 셋이다. 각 ndarray는 같은 인덱스끼리 매칭이 된다. 예를 들면 perch_length 의 첫번째 길이 8.4cm에 해당하는 농어의 무게는 perch_weight의 첫번째 무게 5.9g으로 매칭되는 것이다. 

 

우선 앞선 포스팅에서도 행했듯이 KNN을 사용한 machine learning은 supervised_learning이기 때문에 우리는 데이터와 함께 그 데이터에 대한 답지도 학습을 시켜줘야한다. 예를 들면 길이가 8.4cm인 농어의 무게는 5.9g이야!라고 컴퓨터에게 알려줘야 하는 것이다. 

그렇기 때문에 나는 데이터들을 훈련 세트와 테스트 세트 훈련 세트의 답지와 테스트 세트의 답지로 나눌 것이다. 

scikit-learn라이브러리의 함수 train_test_split함수를 이용해서 수행하겠다. 

2. 훈련 데이터와 테스트 데이터로 나누기 

from sklearn.model_selection import train_test_split

# 훈련 세트와 테스트 세트로 나눕니다.
train_input, test_input, train_target, test_target = train_test_split(
    perch_length, perch_weight, random_state=42)
#랜덤으로 훈련세트와 테스트 세트를 나눈다. target은 답지에 해당한다.

random_State를 42로 주었기 떄문에 훈련세트의 수는 42가 될 것이고 총 데이터의 수가 56이기 때문에 test세트의 데이터 수는 14가 될 것이다. 

다음은 train_test_split함수를 통해 random하게 나눠진 train_input과 test_input이다. 행이 1인 행렬의 형태에 해당하는 것을 확인할 수 있다. 

3. 데이터 구조 변경

# 훈련 세트와 테스트 세트를 2차원 배열로 바꿉니다.
train_input = train_input.reshape(-1, 1)
test_input = test_input.reshape(-1, 1)
print(train_input.shape, test_input.shape)
# scikit - learn을 사용하기 위해서는 2차원 배열이어야하기 때문이다.
# 여기에서는 농어의 길이 데이터 만을 이용해 농어의 무게를 예측할 것이기 때문에 특성이 1개만 쓰인다.
# 따라서 reshape함수를 사용하여 모양을 변경해준다.
# 학습 중

scikit-learn 라이브러리를 사용하기 위해서는 2차원 배열이어야하기 때문에 reshape함수를 이용하여 데이터들의 구조를 행이 1인 행렬에서 열이 1인 행렬로 transpose시켜준다. 

변환된 행렬을 보면 열이 1인 행렬로 변환된 것을 확인할 수 있다. 

4. knr 훈련

K-neighbors-Regression모델을 훈련시키는 함수 또한 KNN모델과 동일하게 fit이라는 api를 사용한다. 우리는 supervised learning을 통해 모델을 학습시키기 때문에 train_Data와 동시에 train_target이라는 정답지도 학습시켜줘야한다. 고려한 neighbor의 수는 3으로 설정해줬다. 

knr = KNeighborsRegressor(n_neighbors=3)
knr.fit(train_input, train_target)
print("knr의 예측 값")
print(knr.predict([[50]]))

그 후 길이가 50cm인 농어의 무게를 예측해보면 다음과 같이 나온다. 

1033.3333g으로 모델은 예측을 하였다. 물론 농어의 무게가 길이라는 하나의 변수의 영향만을 받지는 않을 것이다. 하지만 목적은 Regression에 대한 공부이기 때문에 하나의 변수만을 고려하는 것이다. 

5. 훈련 모델 확인

# 50cm 농어의 이웃을 구합니다.
distances, indexes = knr.kneighbors([[50]])

# 훈련 세트의 산점도를 그립니다.
plt.scatter(train_input, train_target)

# 훈련 세트 중에서 이웃 샘플만 다시 그립니다.
plt.scatter(train_input[indexes], train_target[indexes], marker='D')

# 50cm 농어 데이터
plt.scatter(50, 1033, marker='^')
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

우리는 fit api를 통해 학습한 결과를 그래프로 나타내기 위해 matplotlib 라이브러리를 사용해 그래프를 그릴 것이다. 

knr.kneighbors를 통해 50이라는 새로운 데이터를 넣었을 때 그 주변의 이웃과의 distance와 이웃들의 index를 알아낸다. 

그 후 훈련 세트의 전체 데이터 셋을 그리고 새로운 데이터의 이웃들만을 다시 특별하게 그린 후 그래프를 그리면 다음과 같다. 

결과를 살펴보면 초록색 세모에 해당하는 새로운 데이터들에 가장 가까운 데이터 3개가 주황색 마름모로 표시된 것을 확인할 수 있다. 자 여기서 knr의 치명적인 단점이 나오게 된다. 이미 학습되어진 데이터의 수가 충분하지 않다면 새로운 데이터로 기존의 측정치와 좀 떨어진 데이터가 들어왔을 때 KNR모델은 아주 동떨어진 값을 반환하게 된다. kneighbors란 가장 가깝게 위치하는 데이터들의 평균을 구해 새로운 데이터의 값을 예측하기 때문이다. 또한 새롭게 들어온 데이터가 최대값이나 최솟 값을 가지는 경우 기존의 데이터에서 가장 가까운 데이터들의 평균을 구하기 때문에 input은 최대값이나 최소값이 들어갔지만 예측치는 최대값이나 최소값이 나오지 못한다는 문제도 존재한다. 

6. LinearRegression()

scikit-learn라이브러리의 LinearRegression()함수를 사용하여 학습을 다시 시켜보겠다. 

lr = LinearRegression()
# 선형 회귀 모델 훈련
lr.fit(train_input, train_target)
LinearRegression()
# 50cm 농어에 대한 예측
print(lr.predict([[50]]))

그 후 길이 50cm에 대한 농어의 무게를 예측해보면 어떻게 나올 것인가

아까 1033.333보다 더 큰 1241.8로 예측을 하였다. 이는 knr의 모델은 가장 가까운 데이터들의 평균을 통해 새로운 데이터의 regression값을 계산하지만 LinearRegression모델은 기존의 데이터들을 일차 함수의 그래프로 만들고 그 함수의 기울기와 y절편을 이용한다. 따라서 knr과 달리 최대값의 새로운 데이터 인풋을 넣어도 최대의 예측값이 나올 수 있는 것이다. 

다음 포스트에서는 Linear Regression 모델을 통해 학습하는 결과를 살펴볼 것이다. 

728x90
반응형

댓글