기계 학습 (선형 회귀 함수)

  • by

기계 학습(기계 학습)

  • 지도 학습 : 라벨이 지정된 데이터로 학습 ex.분류, 회귀
  • 비지도 학습: 라벨이 없는 학습 데이터의 숨겨진 구조/특징 발견 ex. 쿨래스터링
  • 강화 학습 : 보상 시스템에서 배우는 ex.위조 지폐 작성 시스템<->위조 지폐 여과 시스템

선형 회귀 (y = Wx+b)

  • 손실 함수가 최소값(=오차 작음)을 갖도록(W, b)를 구하는 것이 최종 목적
  • 기울기 하강 방법: 손실 함수가 최소값을 찾는 방법
    손실 함수의 순간 기울기가 -면 W 증가, +면 W 감소, 기울기가 0이 되도록
  • 학습률은 움직이는 정도(증감되는 비율)를 나타내며, 너무 크더라도 너무 작지 않다(밖으로 흩어지거나 발을 디딘다)
  • 규제는 일반적인 선형 회귀의 과적합 문제를 해결하기 위해 회귀 계수에 페널티 값을 적용합니다.


    (과적합: 학습 데이터에 대해서만 정확하게 예측 가능하고 새로운 데이터는 불가능한 상태) – 데이터는 보편적이고 일반적이어야 하며, 적합하면 W가 커지는 경향이 있음
    L2 규제는 제곱, L1 규제는 절대값을 사용

회귀 직선을 구하는 함수 생성(회귀 직선은 y=6+4*X로 설정되며 이 직선을 추정해야 함)

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(0)
X = 2 * np.random.rand(100,1) # rand: 균일분포
y = 6 + 4 * X + np.random.randn(100,1)  # randn:정규분포
					# noise,error 더해줌
plt.scatter(X,y)


데이터 유형

경사 하강법

① 임의의 가중치 W 선택

②그 W에서의 직선의 기울기를 나타내는 미분치(해당 W에서의 미분, 𝜕𝐸(𝑊)/𝜕𝑊)를 구한다

③그 미분값이 작아지는 방향으로 W감소(또는 증가)시켜 나가면

④ 최종적으로 기울기가 더 이상 작아지지 않는 곳을 찾을 수 있지만, 거기가 손실 함수 E(W) 최소값인 것을 알 수 있다.

# 비용함수 = 편차 제곱 합
def get_cost(y,y_pred):
    N = len(y)
    cost = np.sum(np.square(y-y_pred))/N
    return cost
    
# 경사하강법 (w1: 회귀계수, w0: bias)
def get_weight_update(w1,w0,X,y,learning_rate=0.01):
    N = len(y)
    w1_update = np.zeros_like(w1) # 임의의 값 0으로
    w0_update = np.zeros_like(w0) 
    y_pred = np.dot(X,w1.T)+w0 # 행렬 곱
    diff = y - y_pred
    w0_factors = np.ones((N,1)) # 1로 채워진 N행 1열
    # 미분
    w1_update = -(2/N)*learning_rate*(np.dot(X.T,diff))
    w0_update = -(2/N)*learning_rate*(np.dot(w0_factors.T,diff)) # 1로 채워진 행렬이므로 행렬곱 결과는 diff
    return w1_update,w0_update
    
# iters = 실행 횟수
def gradient_descent_steps(X,y,iters=10000):
    w0 = np.zeros((1,1))
    w1 = np.zeros((1,1))
    for ind in range(iters):
        w1_update,w0_update = get_weight_update(w1,w0,X,y)
        w1 = w1 - w1_update # +가 나오면 빼줘야하고 -가 나오면 더해줘야하므로 -
        w0 = w0 - w0_update
    return w1,w0

실행 횟수가 클수록 미리 설정된 회귀 직선에 가까워지고 비용 함수의 값이 작아집니다.


데이터에 선형 회귀선을 더한 그래프

라이브러리를 이용한 선형 회귀 (보스턴 주택 가격 예측)

데이터 준비

from sklearn import linear_model
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_boston
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error,r2_score

boston = load_boston()
bostonDf = pd.DataFrame(boston.data,columns=boston.feature_names)
bostonDf('PRICE')=boston.target

lm_features = ('RM','ZN','INDUS','NOX','AGE','PTRATIO','LSTAT','RAD')
fig,axs = plt.subplots(figsize=(16,8),ncols=4,nrows=2)
for i,feature in enumerate(lm_features):
    row = int(i/4)
    col = i%4
    sns.regplot(x=feature,y='PRICE',data=bostonDf,ax=axs(row)(col))


그래프를 보면 RM과 LSTAT을 제외한 다른 변수는 주택 가격과 큰 상관 관계가 없음을 알 수 있습니다.

데이터 전체에서 학습하는 데이터와 테스트할 데이터를 구별

y_target = bostonDf('PRICE')
X_data = bostonDf.drop(columns="PRICE")
X_train,X_test,y_train,y_test = train_test_split(X_data,
                                                 y_target,
                                                 test_size=0.3,
                                                 random_state=156)

학습 후, mse(평균 제곱 오차)와 rmse(뿌리의 평균 제곱 오차), r2(예측값 분산/실제 데이터 분산)를 조사한다.

나머지 지표는 작을수록 좋지만 r2 점수는 1에 가까울수록 좋습니다.

lr = LinearRegression()
lr.fit(X_train,y_train)
y_preds = lr.predict(X_test)
mse = mean_squared_error(y_test,y_preds)
rmse= np.sqrt(mse)
r2 = r2_score(y_test,y_preds)
print(f'mse:{mse:.3f},rmse:{rmse:.3f},r2:{r2:.3f}')	# mse:17.297,rmse:4.159,r2:0.757
print('절편:',lr.intercept_)
print('회귀계수:',np.round(lr.coef_,1))
절편: 40.99559517216473
회귀계수: ( -0.1   0.1   0.    3.  -19.8   3.4   0.   -1.7   0.4  -0.   -0.9   0.
  -0.6)


coeff = pd.Series(data=np.round(lr.coef_,1),index=X_data.columns)
coeff.sort_values(ascending=False)


from sklearn.model_selection import cross_val_score
y = bostonDf('PRICE')
X = bostonDf.drop(columns="PRICE")
lr = LinearRegression()
neg_mse = cross_val_score(lr,X,y,scoring='neg_mean_squared_error',cv=5)
# 분류에서도 쓰고 회귀에서도 씀 분류에서는 cross_val_score 커야 좋음
# 회귀는 오차가 작아야 좋은거니까 나온 수치에 - 처리 그래서 neg 붙음 
np.mean(-neg_mse) # 교차검증, mse
# 37.13180746769912
np.sqrt(np.mean(-neg_mse)) # 교차검증, rmse
# 6.093587405436892