Yeonnnnny

[ML] 회귀분석 모델 본문

Machine Learning/지도 학습

[ML] 회귀분석 모델

yeonny_do 2023. 11. 16. 19:42

■ 회귀분석 (Regression Analysis)

 

   □ 정의 

    :매개변수 모델을 이용하여 통계적으로 변수들 사이의 관계를 추정하는 분석방법

 

   □ 용도

    - 독립변수가 종복변수에 미치는 영향을 확인하고자 사용하는 분석방법

    - 종속변수와 관련이 있는 독립변수를 찾을 때, 또 독립변수들 간의 관계를 이해하고자 할 때 사용

    - 가격, 주가, 수량 등 연속적인 값을 갖는 연속 변수를 예측하는데 주로 활용

 

   □ 종류 

    - 단순회귀분석 : 하나의 종속변수와 하나의 독립변수 사이의 관계를 분석할 때 

    - 다중회귀분석  :하나의 종속 변수와 여러 독립변수 사이의 관계를 규명하고자 할 때

 

■ 선형관계

 

 : 독립변수가 종속변수에 영향을 준다면 두 변수 사이에 선형관계가 있다고 할 수 있음

  ex) 속도와 거리, 섭씨와 화씨, 지름과 원의 둘레, 온도와 아이스크림 판매 수, 소득 증가에 따른 소비의 증가

 

 

■ 회귀분석 모델

 

 □ 목적

     - 독립변수와 종속변수 데이터가 주어졌을 때, 두 변수의 관계를 설명할 수 있는 y=wx+b 라는 선형 관계를 찾는 것

     - 이와 같은 선형관계를 알고 있다면, 새로운 x값이 주어졌을 때 종속변수 y의 값을 예측할 수 있음

     - 최소제곱법을 통해 오차를 최소화할 수 있는 w(가중치)와 b(오차)를 찾음 

 

 

 

 

- 회귀식 (모델)  :  y = wx + b

 

- 최소제곱법 : 회귀선과 관측값들의 잔차를 제곱하여 더한 값으로 그 값이 최소가 되도록 회귀계수를 구하는 것

 

- 설명력 지표 : 피어슨 상관계수, 결정계수 R^2

 

 

 

 

 

   □  최소 제곱법

     : 오차의 제곱의 합

 

 ※ 오차를 측정하는 방법으로 대표적으로  절댓값과 최소제곱법이 있는데, 절댓값을 사용하지 않는 이유

① 오차를 더 크게 보이게 하기 위한 목적으로 제곱법을 사용함 

② 오차가 최소인 기울기 값을 찾기 위해서는 미분을 해야함. 미분을 통해 최적의 기울기를 구해야 하는데 절댓값 즉, 상수를 미분하면  0이기 때문에 미분가능한 함수를 사용하기 위해 최소제곱법을 사용함.

 

 

   □  오차함수

    : 각 독립변수 별 오차를 계산하는 함수

 

- 실제 처리해야 하는 데이터는 다변량임.

- 데이터를 학습을 시킨 후 최적화된 가중치와 절편으로 모델을 만들어야 함.

- 예측값 : 실제 나온 값

- 오차 : 실제 나온 값과 예측값의 차이

- 가중치를 통해 각각의 레코드(사례) 별로 오차를 하나씩 다 찾아내야 함. (1개의 단위 : 1 epoch)

 

   □  MSE 

    : 비용함수 (평균 제곱오차) , 2차 함수의 형태를 띔 (아래로 볼록한 모형)

 

    - 목적

      : MSE의 값이 최소가 되게 하는 값을 찾는 것

 

    - 방법 :  경사하강법

 ○ 경사를 타고 내려오는 것
 ○ 초기의 가중치 값은 임의로 주어짐 (시스템 내부에서 주어진 데이터 기반으로 임의의 값을 설정함)
 ○ 현재의 위치(비용 곡선의 한 점)에서 미분하여 기울기(가중치) 찾음
 ○ 기울기가 +인지 -인지 확인

    if 기울기 > 0 : 가중치 감소시켜야 함 
    if 기울기 < 0 : 가중치 증가시켜야 함 

  ▷ 가중치의 값을 조절함으로써 손실 즉 오차의 범위를 줄임
  ▷ 손실 최적화점을 찾아야 함

 

    => new Weight = old Weight -  (학습률(이동거리))* 기울기

         : 가중치 업데이트시, 기울기>0 : 가중치 감소함, 기울기<0 : 가중치 증가함

 

※ 학습률(Learning Rate) 및 이동거리

(기울기만으로 가중치를 조정한다면, 이동폭이 아주 크거나 미미할 수 있기 때문에 적절한 값을 곱할 필요가 있음)

- 경사를 타고 내려오는  보폭이라고 정의할 수 있음
-  training되는 양 또는 단계
- 학습데이터를 기반으로 학습 모델 오차에 대한 가중치를 업데이트할 때 사용되는 기준점 중 하나
- 모델이 학습을 진행할 때 각각의 가중치를 얼마나 업데이트할지 결정하는 하이퍼 파라미터
- 매개변수 업데이트 시의 크기를 조절하며 모델이 적절한 방향으로 수렴할 수 있도록 도와줌
- 즉, 가중치 업데이트 크기를 결정하는 요소
- 적절한 학습률을 찾는 것이 중요함. 학습률이 너무 높으면 결과 속도가 빨라지지만 오류값을 제대로 산출해내지 못하거나 오버플로우가 발생할 수 있고, 반대로 학습률이 너무 낮으면 산출되는 결과 속도가 느려지고 오류값이 너무 많아져서 실행과정 자체가 멈줄 수 있음.

 

 ※ 오차 제곱에 대한 평균을 하는 이유 : 오차는 각 사례들에 대한 것임. 사례의 개수가 많아질수록 오차에 대한 데이터도 많아지고 범위도 커질 것이기 때문에 평균을 내서 오차를 파악하는 것임 

 

 

비용함수 

 

 
# Cost Function : 오차 제곱 평균 함수
# w : 가중치 (초기 : 임의값)
# x : 독립변수 (리스트)
# y : 종속변수 (리스트)
# b : 절편 (초기 : 임의값)

def MSE(w,x,y,b):
    s = 0
    for i in range(len(x)) :  # 원소 개수 만큼 반복문 돌림
        s+=(y[i]-(w*x[i]+b))**2
    return s/len(x)           # 오차 제곱의 평균

# y = 2x + 0.1
x = [1.,2.,3.]         # 독립변수, Feature
y = [2.1,4.1,6.1]      # 종속변수, Label
b = 0.1

w_val = []     # 가중치 저장할 리스트
cost_val = []  # 비용함수 저장할 리스트

for w in np.linspace(-4,8,20):  # .linspace() : 균등분배 => -4~8까지 임의로 20개 균등 분배한 값
    c = MSE(w,x,y,b)
    w_val.append(w)
    cost_val.append(c)

### cost 값을 이용한 그래프 그리기
plt.plot(w_val,cost_val)
plt.xlabel('Weight')
plt.ylabel('Cost')
plt.show() # w 값이 2일 때 최적

 

가중치 학습

 

 
from sklearn.datasets import load_diabetes # 당뇨병관련 데이터들이 딕셔너리 형태로 저장되어 있음(기본 모듈)
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

diabetes = load_diabetes() # 당뇨병 환자 데이터 로드
df = pd.DataFrame(diabetes.data, columns = diabetes.feature_names)
df.head() # 값이 float으로 된 이유 : 이미 스케일링된 데이터이기 때문
 

 

 

 

 
df['target'] = diabetes.target  # 타겟 컬럼 추가
df.head()


w = 1.0  # 초기 가중치
b = 1.0  # 초기 절편

print(df['bmi'].min(),df['bmi'].max())  # bmi 컬럼의 최솟값, 최댓값

start = (-0.1, -0.1*w+b)   # 회귀선의 시작점(x,y) : 튜플의 형태임
end = (0.16, 0.16*w+b)     # 회귀선의 끝점(x,y)

plt.plot([start[0],end[0]],[start[1],end[1]],'r')  # plot([x좌표 리스트],[y좌표 리스트])

plt.scatter(df['bmi'],df['target'])
plt.xlabel('bmi')
plt.ylabel('target')
plt.show()
 

 

 

학습 전

 

 

 
# 학습

for i in range(100) :  # 100번 반복해서 학습
    for x_i, y_i in zip(df['bmi'],df['target']):
        y_hat = w*x_i+b        # 예측값
        w-=(y_hat-y_i)*x_i     # w에 대한 미분식을 이용해 가중치 업데이트
        b-=(y_hat-y_i)         # b에 대한 미분식(b : 상수x, 가중치가 0일때 존재하는 오차)

start = (-0.1, -0.1*w+b)  
end = (0.16, 0.16*w+b)    

plt.plot([start[0],end[0]],[start[1],end[1]],'r')

plt.scatter(df['bmi'],df['target'])
plt.xlabel('bmi')
plt.ylabel('target')
plt.show()
 

 

 

학습 후

 

단변량 데이터의 Linear Regression (Scikit-learn 이용)

 

 
from sklearn.linear_model import LinearRegression
import pandas as pd
import numpy as np

# 1) 데이터 준비
x = np.array([1,3,2,4,7,4,9,2,3,2,6,3,2,7])
x = np.expand_dims(x,axis=1)
y = np.array([3,9,6,7,10,6,12,2,4,3,8,5,3,10])

# 2) 모델 준비
model = LinearRegression()

# 3) 학습(fitting)
model.fit(x,y)       # y = wx + b

# 4) 평가
r_square = model.score(x,y)
print('R-square :',r_square)

# 5) 예측(추론)
x_new = [[7]]
y_hat = model.predict(x_new)
print('예측값 :',y_hat)
print('정답 : 10')
 

  

 

Linear Regression

 

 
# 모듈 불러오기
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
 

 

 
# 1) 데이터 준비
np.random.seed(0)
x = np.random.rand(100,1)*10    # [0,100)범위의 (100,1)행렬 생성
y = (x*2.3) + np.random.rand(100,1)*5.4  # 회귀선

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

# 2) 모델 준비
model = LinearRegression()

# 3) 학습 데이터, 평가 데이터 분리
x_train, x_test, y_train, y_test = train_test_split(x,y,test_size=0.3,random_state=10)
# train_size : 0.7
# random_state : 지정하지 않으면, 위의 경우 훈련,평가를 7:3으로 나눌 때 그냥 임의로 70개, 30개 뽑음. 즉, 실행을 돌릴 때마자 분할된 값들이 달라짐
# 그래서 임의의 전수를 넣어주면 재실행해도 늘 똑같은 값들로 분할됨. random.seed와 같은 원리

# 4) 학습
model.fit(x_train,y_train)  # 단변량 데이터

# 5) 평가
r_square = model.score(x_test,y_test)
print(f'결정계수 : {r_square:.2f}')
print(f'추정계수(가중치) : {model.coef_}')
print(f'절편 : {model.intercept_}')

# 6) 예측 및 시각화
plt.plot(x,y,'o')
plt.plot(x,model.predict(x),'r')
plt.show()


 

 

데이터 준비 단계

 

평가 단계

 

최종

 

 

  □  회귀모델의 평가지표

 

 MAE (Mean Absolute Error)

: 각 오차의 절댓값의 평균

: 오차가 얼마나 나오는지 알고 싶을 때 

 

 RMSE (Root Mean Squared Error)

: 오차의 제곱의 합의 평균

: 오차가 얼마나 나오는지 알고 싶을 때 

 

 R^2 (결정계수) 

: 1-(잔차의 제곱의 합 /편차의 제곱의 합) ,

: 일반적으로 0~1사이의 값을 가짐.  값이 1에 가까울수록 설명변수가 종속변수를 잘 설명한다고 볼 수 있음

: 수치가 얼마나 좋은지 알고 싶을 때

 

 

 

[문제] 키와 몸무게를 이용해 모델을 학습시킨 후 키 170인 사람의 몸무게를 예측하는 프로그램 작성

 

 
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error,r2_score,mean_squared_error
 
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
 
import warnings
warnings.filterwarnings(action ='ignore')
 
 
# 1) 데이터 준비
df = pd.read_csv('body.csv')
display(df.head())
x =df[['Height']]
# x = df['Height'].values.reshape(-1,1)   # 위와 동일한 결과 
y =df['Weight']
 

 

body.csv : Height, Weight 정보 담긴 파일

 

 
# 2) 모델 준비
model = LinearRegression()

# 3) 학습, 평가 데이터 나누기
x_train,x_test,y_train,y_test = train_test_split(x,y,train_size=0.7,random_state=10)

# 4) 학습
model.fit(x_train,y_train)
 
# 5) 평가
r_square = model.score(x_test,y_test)
print(f'결정계수 : {r_square:.3f}')
print(f'추정계수(가중치) : {model.coef_}')
print(f'절편(가중치) : {model.intercept_}\n')

y_hat = model.predict(x_test)   # 예측값
 
# mean_absolute_error (정답, 예측값) : 평균(sum(abs(오차)))
print(f'MAE : {mean_absolute_error(y_test, y_hat):.3f}')
 
# np.sqrt(mean_squared_error(정답, 예측값)) : sqrt(mean(sum(오차**2)))
print(f'RMSE : {np.sqrt(mean_squared_error(y_test, y_hat)):.3f}')
 
# r2_score(정답, 예측값) : 모델의 설명력
print(f'r2 score : {r2_score(y_test, y_hat):.3f}')
 

 

 


# 6) 예측(추론) - 170의 체중 예측
x_new = [[170]]
y_hat = model.predict(x_new)
print('예측값 :',y_hat)
 

 

 
# 7) 시각화
plt.plot(x,y,'o')
plt.plot(x,model.predict(x),'r')
plt.show()
 

 

 

 

 

[실습] California 집값 예측- 1990년 캘리포니아 블록 그룹마다 주택 가격 데이터

 

 

  # 방법 1) model을  LinearRegression() 으로 생성한 경우

 

 
from sklearn.linear_model import LinearRegression
# RandomForestRegressor : 집단 지성을 이용한 모듈(여러 개의 모형 -> 다수 결 원칙 -> 결과 결정)
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_absolute_error,mean_squared_error,r2_score
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns


# 1) 데이터 준비
# 학습데이터
data = pd.read_csv('california_housing_train.csv')
print(data.shape)
display(data.head())
x=data[data.columns[2:-1]]
y=data['median_house_value']
 

 

 

 
# 2) 모델 준비
model = LinearRegression()

# 3) 학습
model.fit(x,y)

# 4) 평가
# 평가데이터 불러오기
test_data = pd.read_csv('california_housing_test.csv')
x_test = test_data[test_data.columns[2:-1]]
y_test = test_data['median_house_value']

print(f'R square : {model.score(x_test,y_test)}\n')

# 5) 예측
predict_data = x_test[10:11] # 10행의 설명변수들만 넣어서 확인해보기
y_hat = model.predict(predict_data)

print('예측값 :',y_hat)
print('실제값 :',y_test[10])


 

 

 
# 6) 시각화
y_hat = model.predict(x_test)
plt.figure(figsize=(10,5))
sns.kdeplot(y_test, label='y', fill=True)
sns.kdeplot(y_hat, label='y_hat', fill=True)
plt.legend()
plt.show()
 

 

 

 

 

 

   # 방법 2) model을  RandomForestRegression() 으로 생성한 경우

 

 
from sklearn.linear_model import LinearRegression
from sklearn.ensemble import RandomForestRegressor# 집단 지성 이용하는 모듈(여러 개의 모형->다수결 원칙->결과 결정)
from sklearn.metrics import r2_score, mean_absolute_error, mean_squared_error
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# 1) 데이터 준비
# 학습 데이터
data = pd.read_csv('california_housing_train.csv')
print(data.shape)
display(data.head())
x = data[data.columns[2:-1]]
y = data['median_house_value']

# 2) 모델 준비
model = RandomForestRegressor() # 의사결정나무를 1000개를 돌림

# 3) 학습'
model.fit(x,y)

# 4) 평가
# 평가 데이터
test_data = pd.read_csv('california_housing_test.csv')
print(test_data.shape)
test_x = test_data[test_data.columns[2:-1]]
test_y = test_data['median_house_value']

print(f'R스퀘어 : {model.score(test_x,test_y)}')

# 5) 예측
predict_data = test_x[10:11]
y_hat = model.predict(predict_data)

print('예측값 :',y_hat)
print('실제값 :',test_y[10])


# 6) 시각화
y_hat = model.predict(test_x)
plt.figure(figsize=(10,5))

# kdeplot : 확률 밀도 그래프 : 히스토그램과 유사하지만, 각 데이터의 구간 별 빈도수를 확률적으로 추정하여 부드러운 곡선으로 나타냄
sns.kdeplot(test_y, label = 'y', fill=True)
sns.kdeplot(y_hat, label = 'y_hat', fill=True)
plt.legend()
plt.show()
 

 

※ Linear Regression()을 사용한 것보다 결정계수의 값이 상승했음. 의사결정나무가 데이터들을 설명하는데 보다 적합함.

 

 

 

 


Reference : https://sesoc.tistory.com/137?category=891417

 

'Machine Learning > 지도 학습' 카테고리의 다른 글

[ML] 분류분석 - KNN  (0) 2023.11.27
[ML] 앙상블 러닝  (0) 2023.11.27
[ML] 분류분석 - 의사결정트리  (1) 2023.11.27
[ML] 분류 분석 - 나이브 베이즈 분류  (0) 2023.11.27
[ML] 분류분석 - 이진분석  (1) 2023.11.26