상세 컨텐츠

본문 제목

머신러닝 (7) - Regression(회귀)

IT/Machine Learning

by HarimKang 2020. 2. 12. 14:39

본문

Writer: Harim Kang

해당 포스팅은 머신러닝에서 사용되는 Regression, 회귀를 공부하면서 직접 코드를 작성해본 실습 위주의 내용입니다. 선형 회귀의 경우에는 Numpy, Tensorflow2.0, sklearn 라이브러리를 사용하여 세가지 방법으로 구현해보았고, 다항 회귀Tensorflow2.0, sklearn 라이브러리를 사용하여 두가지 방법을 사용해보았습니다.

Regression (회귀)

회귀는 기본적인 데이터 분석 방법입니다. 짧게 정의하자면, 가격이나 확률처럼 연속된 실숫값을 정확히 예측하는 것을 목적으로 가진 방법입니다.

최소제곱법(Least Square Method)

  • 하나의 함수와 각 데이터의 차를 잔차(Residual)라고 합니다.
  • 잔차들의 제곱을 최소화하는 알고리즘을 최소제곱법이라고 합니다.

  • 위와 같은 공식의 최솟값을 찾는 방법입니다. y-y_pred를 잔차(residue)라고합니다.
  • 최소제곱법을 사용하여 특정 차수의 함수의 계수를 찾는 것을 회귀선을 구하는 것이라고 볼 수 있습니다.

Linear Regression

  • 선형 회귀는 데이터 전체의 경향을 나타내는 2차원의 직선을 예측하는 것을 의미합니다. 데이터의 경향이 선형적인 관계라고 생각되면 사용합니다.
  • 정의를 살펴보자면, 종속 변수(dependent variable)와 하나 이상의 독립 변수(independent variavle)사이의 관계를 모델링하는 선형적인(linear) 접근 방식을 의미합니다.

Test 환경

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

x = 2 * np.random.rand(100, 1)
y = 4 + 3 * x + np.random.randn(100, 1)

plt.plot(x, y, 'bo')
plt.show()

x값은 0부터 2까지의 랜덤한 값을 선언하였고, y=3x+4 경향에 가깝도록 y=3x+4+randn 값을 선언하였습니다.

Numpy를 사용한 선형 회귀

x_mean = sum(x) / len(x)
y_mean = sum(y) / len(y)

a = sum([(x_ - x_mean) * (y_ - y_mean) for x_, y_ in list(zip(x, y))])
a /= sum([(x_ - x_mean) ** 2 for x_ in x])
b = y_mean - a * x_mean
print('a:', a, 'b:', b)

x_pred = np.arange(min(x), max(x), 0.01)
y_pred = a * x_pred + b

plt.plot(x_pred, y_pred, 'r-')
plt.plot(x,y,'bo')
plt.show()

위에서 설명한 최소제곱법의 공식을 이용하여 코드를 작성하였습니다. x_pred는 x값들을 numpy배열로 바꾼것이고, y_pred는 최소제곱법을 사용하여 계산한 a와 b를 사용하여 계산한 값입니다.

a가 3에 가깝고, y절편인 b가 4에 가깝게 계산되었습니다.

Tensorflow를 사용한 선형 회귀

import random

w = tf.Variable(random.random())
b = tf.Variable(random.random())

우선 가중치와 편향을 랜덤 값으로 초기화를 하였습니다.

def residue():
  y_pred = w * x + b
  re= tf.reduce_mean((y - y_pred) ** 2)
  return re

잔차(residue)를 구하는 함수입니다. 예측 값과 실제 데이터 값의 차이를 제곱한 값의 합을 구하여 이것의 평균을 re로 return합니다.

optimizer = tf.optimizers.Adam(lr=0.07)
for i in range(1000):
  optimizer.minimize(residue, var_list=[w,b])

  if i % 100 == 99:
    print(i, 'w:', w.numpy(), 'b:', b.numpy(), 'loss:', residue().numpy())

손실을 최소화하는 최적화 함수(optimizer)입니다. 해당 함수는 복잡한 미분 계산 및 가중치 업데이트를 자동으로 진행해주는 함수입니다. 해당 포스팅에서는 Adam 최적화 함수를 선정하였습니다. SGD와 함께 많이 쓰이는 함수로서, 좋은 성능을 보여줍니다. lr(learning rate)는 보통 0.1에서 0.0001 사이 값을 사용하는 데, 0.07을 사용하겠습니다.

optimizer.minimize(residue, var_list)는 var_list로 받은 변수 리스트를 residue함수가 최소가 되도록 1000번 학습하는 것입니다. 값의 변화를 확인하기 위해서, 100번에 한번씩 출력해보았습니다.

위의 결과를 토대로 그래프를 그려보면 아래와 같습니다.

x_pred = np.arange(min(x), max(x), 0.01)
y_pred = w * x_pred + b

plt.plot(x_pred, y_pred, 'r-')
plt.plot(x, y, 'bo')
plt.show()

numpy로 계산한 a,b와 텐서플로우로 계산한 w,b가 완전히 일치하진 않지만, 아주 유사함을 확인할 수 있습니다.

sklearn을 사용한 선형 회귀

from sklearn.linear_model import LinearRegression

lin_reg = LinearRegression()
lin_reg.fit(x, y)
print(lin_reg.intercept_, lin_reg.coef_)

sklearn 라이브러리는 LinearRegression을 위한 자체적인 모델을 제공합니다. fit함수를 통해서 데이터를 입력시켜주면됩니다.

numpy 계산과 일치하게, tensorflow 계산과는 유사하게 결과가 나왔습니다. 이를 그래프로 나타내보면 아래와 같습니다.

x_pred = np.array([[0], [2]])
y_pred = lin_reg.predict(x_pred)

plt.plot(x, y, 'bo')
plt.plot(x_pred, y_pred, 'r-')
plt.show()

Polynomial Regression

  • 다항 회귀(Polynomial Regression)은 선형회귀의 직선을 2차 함수 이상으로 예측하는 것을 의미합니다.

Test 환경

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

x = 2 * np.random.rand(100, 1)
y = 6 * (x ** 2) + 3 * x + 4 + np.random.randn(100, 1)
plt.plot(x, y, 'bo')
plt.show()

이번엔 이차함수인 y=6x^2+3*x+4 경향이 나타나도록 랜덤값들을 데이터로 만들어보았습니다.

Tensorflow를 사용한 다항 회귀

import random

w = tf.Variable(random.random())
b = tf.Variable(random.random())
c = tf.Variable(random.random())

def residue():
  y_pred = w * x**2 + b * x + c
  loss = tf.reduce_mean((y - y_pred) ** 2)
  return loss

optimizer = tf.optimizers.Adam(lr=0.07)
for i in range(1000):
  optimizer.minimize(residue, var_list=[w,b,c])

  if i % 100 == 99:
    print(i, 'w:', w.numpy(), 'b:', b.numpy(), 'c:', c.numpy(), 'loss:', residue().numpy())

선형 회귀와 유사합니다. 달라진 점은 c라는 변수의 추가와 y식의 변화입니다.

학습이 좀 더 진행된다면 더 낮은 손실과 정확한 값들을 찾을 수 있습니다.

x_pred = np.arange(min(x), max(x), 0.01)
y_pred = w * x_pred * x_pred + b * x_pred + c

plt.plot(x_pred, y_pred, 'r-')
plt.plot(x, y, 'bo')
plt.show()

sklearn을 사용한 다항 회귀

sklearn에서는 LinearRegression은 제공합니다. 해당 클래스와 다항 회귀를 위해서 기존 데이터를 다항 회귀에 적합한 데이터로 바꾸어주는 PolynomialFeatures 클래스를 이용하여 다항 회귀 모델을 추정할 수 있습니다.

from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression

poly_features = PolynomialFeatures(degree = 2, include_bias=True)
x_poly = poly_features.fit_transform(x)

lin_reg = LinearRegression()
lin_reg.fit(x_poly, y)

x_new = np.linspace(0, 2, 100).reshape(100,1)
x_new_poly = poly_features.transform(x_new)
y_predict = lin_reg.predict(x_new_poly)

plt.plot(x_new, y_predict, "r-")
plt.plot(x, y, "bo")
plt.show()

식의 차수를 늘리고, 변수를 늘리면, 3차 이상의 다항 함수들의 회귀도 가능합니다. 이것은 데이터의 형태를 파악한 후에, 적절한 차수를 선택하면 좋을 것 같습니다.

딥러닝 네트워크를 이용한 회귀(Regression)은 아래의 포스트에서 확인할 수 있습니다.

2020/02/12 - [IT/Deep Learning] - 딥러닝 (4) - 회귀(Regression) 네트워크 만들기

 

딥러닝 (4) - 회귀(Regression) 네트워크 만들기

Writer: Harim Kang 해당 포스팅은 '시작하세요! 텐서플로 2.0 프로그래밍'책의 흐름을 따라가면서, 책 이외에 검색 및 다양한 자료들을 통해 공부하면서 정리한 내용의 포스팅입니다. 해당 내용은 딥러닝을 이용..

davinci-ai.tistory.com

위의 실습 내용들은 아래의 깃허브 링크를 통해서 확인 하실 수 있습니다.

https://github.com/harimkang/tensorflow2_deeplearning/blob/master/regression_1.ipynb

 

harimkang/tensorflow2_deeplearning

tensorflow2, deep learning study example codes. Contribute to harimkang/tensorflow2_deeplearning development by creating an account on GitHub.

github.com

Reference

최소제곱법: https://ko.wikipedia.org/wiki/최소제곱법

관련글 더보기

댓글 영역