도찐개찐

[Python] 선형회귀 본문

PYTHON/데이터분석

[Python] 선형회귀

도개진 2022. 12. 26. 13:01

선형회귀 기본 개념

  • 함수란 두 집합 사이의 관계를 설명하는 수학 개념입니다.
    • 변수 x와 y가 있을 때, x가 변하면 이에 따라 y는 어떤 규칙으로 변하는지 나타냅니다.
    • 일차 함수는 y가 x에 관한 일차식으로 표현된 경우를 의미
  • 일차 함수식 y = ax + b에서 a는 기울기, b는 절편이라고 합니다.
    • 기울기는 기울어진 정도를 의미하는데, x 값이 증가할 때 y 값이 어느 정도 증가하는지에 따라 정해짐
    • 절편은 그래프가 축과 만나는 지점을 의미
  • x가 주어지고 원하는 y 값이 있을 때 적절한 a와 b를 찾는 것 - 머신러닝 핵심
  • 이차 함수란 y가 x에 관한 이차식으로 표현되는 경우를 의미 - 𝑦=𝑎𝑥2y=ax2
  • y = ax2의 그래프를 x축 방향으로 p만큼, y축 방향으로 q만큼 평행 이동시키면 점 p와 q를 꼭짓점으로 하는 포물선이 되겠지요
    • 포물선의 맨 아래에 위치한 지점이 최솟값이 되는데, 딥러닝을 실행할 때는 이 최솟값을 찾아내는 과정이 매우 중요
    • 이 최솟값은 4장에 소개할 ‘최소 제곱법’ 공식으로 쉽게 알아낼 수 있습니다
    • 러닝을 실제로 실행할 때 만나는 문제에서는 대부분 최소 제곱법을 활용할 수가 없습
    • 따라서 미분과 기울기를 이용
  • 미분, 순간 변화율과 미분계수, 기울기
  • 편미분 - 여러 가지 변수가 식 안에 있을 때, 모든 변수를 미분하는 것이 아니라 우리가 원하는 한 가지 변수만 미분하고 그 외에는 모두 상수로 취급하는 것
  • 지수와 지수 함수, 시그모이드 함수, 로그와 로그 함수

 

가장 훌륭한 예측선 - 선형회귀

  • 독립적으로 변할 수 있는 값 x를 독립 변수(feature)라고 합니다.
  • 이 독립 변수에 따라 종속적으로 변하는 y를 종속 변수(label)라고 합니다.
  • 선형 회귀란 독립 변수 x를 사용해 종속 변수 y의 움직임을 예측하고 설명하는 작업
  • 하나의 x 값만으로도 y 값을 설명할 수 있다면 단순 선형 회귀(simple linear regression)라고 합니다.
  • 또한, x 값이 여러 개 필요하다면 다중 선형 회귀(multiple linear regression)라고 합니다.

 

import numpy as np

# 공부한 시간과 중간고사 성적 데이터
# 공부한 시간 2시간 4시간 6시간 8시간
# 성적 81점 93점 91점 97점

x = np.array([2, 4, 6, 8])
y = np.array([81, 93, 91, 97])

# x, y의 평균값을 구합니다.
mx = np.mean(x)
my = np.mean(y)

# 기울기 공식의 분모 부분입니다.
divisor = sum([(i - mx)**2 for i in x])

# 기울기 공식의 분자 부분입니다.
def top(x, mx, y, my):
    d = 0
    for i in range(len(x)):
        d += (x[i] - mx) * (y[i] - my)
    return d
dividend = top(x, mx, y, my)

# 기울기 a를 구하는 공식입니다.
a = dividend / divisor

# y 절편 b를 구하는 공식입니다.
b = my - (mx*a)

a, b

# 결과 : 2.3, 79.0

 

평균 제곱 오차(Mean Square Error, MSE)

  • 오차 = 실제 값 - 예측 값
  • 그래프의 기울기가 잘못되었을수록 빨간색 선의 거리의 합, 즉 오차의 합도 커집니다
  • 만일 기울기가 무한대로 커지면 오차도 무한대로 커지는 상관관계가 있는 것을 알 수 있
  • 선형 회귀란 임의의 직선을 그어 이에 대한 평균 제곱 오차를 구하고, 이 값을 가장 작게 만들어 주는 a 값과 b 값을 찾아가는 작업

 

# 가상의 기울기 a와 y 절편 b를 정합니다.
fake_a = 3
fake_b = 76

# 공부 시간 x와 성적 y의 넘파이 배열을 만듭니다.
x = np.array([2, 4, 6, 8])
y = np.array([81, 93, 91, 97])

# y = ax + b에 가상의 a 값과 b 값을 대입한 결과를 출력하는 함수입니다.
def predict(x):
    return fake_a * x + fake_b

# 예측 값이 들어갈 빈 리스트를 만듭니다.
predict_result = []

# 모든 x 값을 한 번씩 대입해 predict_result 리스트를 완성합니다.
for i in range(len(x)):
    predict_result.append(predict(x[i]))
    print("공부시간=%.f, 실제점수=%.f, 예측점수=%.f" % (x[i], y[i], predict(x[i])))
    
# 평균 제곱 오차 함수를 각 y 값에 대입해 최종 값을 구하는 함수입니다.
n = len(x)  
def mse(y, y_pred):
    return (1/n) * sum((y - y_pred)**2)

# 평균 제곱 오차 값을 출력합니다.
print("평균 제곱 오차: " + str(mse(y, predict_result)))

# 결과
# 공부시간=2, 실제점수=81, 예측점수=82
# 공부시간=4, 실제점수=93, 예측점수=88
# 공부시간=6, 실제점수=91, 예측점수=94
# 공부시간=8, 실제점수=97, 예측점수=100
평균 제곱 오차: 11.0

 

그래프 시각화

fake_a = 3
fake_b = 76
# 기울기를 3, 절편을 76으로 놓고 예측값 계산
z = [(fake_a * v + fake_b) for v in x]
z # 예측값

import matplotlib.pyplot as plt
plt.plot(x, y, 'ro')
plt.plot(x, z, 'b') # 예측선 : 기울기 : 3, 절편 : 76 
plt.show()

결과화면

fake_a2, fake_b2 = 2, 76
z = [(fake_a2 * v + fake_b2) for v in x]
z # 예측값

plt.plot(x, y, 'ro')
plt.plot(x, z, 'b') # 예측선 : 기울기 : 2, 절편 : 76 
plt.show()

# 평균 제곱 오차 값을 출력합니다.
print("평균 제곱 오차: " + str(mse(y, z)))

# 결과 : 
# 평균 제곱 오차: 29.0

결과화면

기울기와 오차

  • 기울기 a를 너무 크게 잡으면 오차가 커지는 것을 확인했습니다.
  • 기울기를 너무 작게 잡아도 오차가 커집니다.
  • 기울기 a와 오차 사이에는 이렇게 상관관계가 있습
  • 기울기가 무한대로 커지거나 무한대로 작아지면 그래프는 y축과 나란한 직선이 됩니다
  • 기울기 a와 오차 사이에는 이차 함수의 관계가 있다는 의미
  • 오차가 가장 작을 때는 언제일까요? 그래프의 가장 아래쪽 볼록한 부분에 이르렀을 때입니다.
  • 바로 미분 기울기를 이용하는 경사 하강법(gradient decent)
  • 우리가 찾는 최솟값 m에서의 순간 기울기
  • 그래프가 이차 함수 포물선이므로 꼭짓점의 기울기는 x축과 평행한 선이 됩니다.
  • 즉, 기울기가 0입니다. 따라서 우리가 할 일은 ‘미분 값이 0인 지점’을 찾는 것이 됩니다.
  • 학습률(learning rate)
  • 어느 만큼 이동시킬지 신중히 결정해야 하는데, 이때 이동 거리를 정해 주는 것이 바로 학습률입니다.
  • 딥러닝에서 학습률의 값을 적절히 바꾸면서 최적의 학습률을 찾는 것은 중요한 최적화 과정 중 하나

기울기와 오차간의 관계 시각화

import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import mean_squared_error

weights = []     # 기울기
loss = []        # 오차
b = 0            # 절편은 0으로 편의상 설정

for w in range(-20, 50) :  # 기울기를 -20 ~ 50까지 설정
    xtrain = np.array([2,4,6,8])
    ytrain = np.array([91,93,91,97])   # 실제값
    ytrain_hat = w * xtrain + b        # 예측값
    
    weights.append(w)
    loss.append(mean_squared_error(ytrain, ytrain_hat))

# 결과 출력 및 그래프 그리기
# print(weights, '\n', loss)

plt.plot(weights, loss)
# plt.axis([-15,45, 0, 30000])
plt.show()

import matplotlib.pyplot as plt

# 기울기 a의 값과 절편 b의 값을 초기화합니다.
a = 0
b = 0

# 학습률을 정합니다.
lr = 0.03

# 전체데이터를 대상으로 학습을 몇 번 반복될지 설정합니다.
epochs = 2001 

# x 값이 총 몇 개인지 셉니다.
n = len(x)

# 경사 하강법을 시작합니다.
for i in range(epochs):      # 에포크 수만큼 반복합니다.
    y_pred = a * x + b       # 예측 값을 구하는 식입니다.
    error = y - y_pred       # 실제 값과 비교한 오차를 error로 놓습니다.

    a_diff = (2/n) * sum(-x * (error))   # 오차 함수를 a로 편미분한 값입니다.
    b_diff = (2/n) * sum(-(error))       # 오차 함수를 b로 편미분한 값입니다.

    a = a - lr * a_diff   # 학습률을 곱해 기존의 a 값을 업데이트합니다.
    b = b - lr * b_diff   # 학습률을 곱해 기존의 b 값을 업데이트합니다.

    #if i % 100 == 0:      # 100번 반복될 때마다 현재의 a 값, b 값을 출력합니다.
    #    print("epoch=%.f, 기울기=%.04f, 절편=%.04f, 오차=%.04f" % (i, a, b, mse(y, y_pred)))
        
# 앞서 구한 최종 a 값을 기울기, b 값을 y 절편에 대입해 그래프를 그립니다.
y_pred = a * x + b      


# 공부 시간 X와 성 y의 넘파이 배열을 만듭니다.
x = np.array([2, 4, 6, 8])
y = np.array([81, 93, 91, 97])

# 데이터의 분포를 그래프로 나타냅니다.
plt.scatter(x, y)
plt.plot(x, y_pred,'r')
plt.show()

728x90

'PYTHON > 데이터분석' 카테고리의 다른 글

[데이터분석] 02. 통계와 데이터  (0) 2023.01.02
[데이터 분석] 01. 통계와 데이터  (0) 2023.01.02
인공지능 개념  (0) 2022.12.26
[Python] folium(지도시각화)  (0) 2022.12.26
[Python] plot 한글 사용  (0) 2022.12.26
Comments