[머신러닝 가이드] 5-1 단순선형회귀
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
np.random.seed(8)
x = 2 * np.random.randn(100,1)
y = 6 + 4 * x + np.random.randn(100,1)
plt.scatter(x,y)
y = 4x + 6 근사
np.random.randn => 표준정규분포에서 값 생성. 100,1 은 값 행렬 형식 선언 입니다.
def get_cost(y, y_pred):
N = len(y)
cost = np.sum(np.square(y-y_pred)) / N
return cost
편차 제곱 평균을 계산해주는 함수.
np.square => 제곱 해주는 함수
def get_weight_updates(w1, w0, x, y, learning_rate = 0.01):
N = len(y)
# w1, w0 동일한 행렬 크기를 갖는 0 값으로 초기화
w1_update = np.zeros_like(w1)
w0_update = np.zeros_like(w0)
#np.dot 행렬의 곱
y_pred = np.dot(x, w1.T) + w0
diff = y - y_pred
w0_factors = np.ones((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))
return w1_update, w0_update
편미분한 w1, w0값을 이용해서 w0, w1값을 지속적으로 업데이트 해줍니다
np.zeros_like(w1) => w1값과 같은 형태에 값은 0인 행렬 생성
np.dot(,) => 행렬 연산
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_updates(w1, w0, x, y, learning_rate=0.01)
w1 = w1 - w1_update
w0 = w0 - w0_update
return w1, w0
위 두 함수를 통해 w1, w0 값을 지속적으로 업데이트 하여 최적에 값에 도달하게 합니다.
w1, w0 = gradient_descent_steps(x,y, 1000)
print('w1 :', np.round(w1[0,0],4), 'w0 :', np.round(w0[0,0],4))
y_pred = w1[0,0] * x + w0
print('편차제곱평균:', np.round(get_cost(y, y_pred),4))
plt.scatter(x,y)
plt.plot(x,y_pred)
경사하강법을 이용해 회귀선이 잘 만들어졌습니다.
다만 데이터에 개수가 100개보다 훨씬 많아지면 전체데이터로 계수를 업데이트 하지 못합니다.
그 때문에 실전에서는 대부분 (미니배치)확률적 경사 하강법을 이용합니다.
이 방식은 전체 데이터가 아닌 일부 데이터로 계수를 업데이트 하기 때문에 속도가 상대적으로 빠릅니다.
이를 구현해보겠습니다.
def stochastic_gradient_descent_steps(x,y,batch_size = 10, iters = 1000):
w0 = np.zeros((1,1))
w1 = np.zeros((1,1))
prev_cost = 100000
iter_index = 0
for ind in range(iters):
np.random.seed(ind)
stochastic_random_index = np.random.permutation(x.shape[0])
sample_x = x[stochastic_random_index[0:batch_size]]
sample_y = y[stochastic_random_index[0:batch_size]]
w1_update, w0_update = get_weight_updates(w1, w0, sample_x, sample_y)
w1 = w1 - w1_update
w0 = w0 - w0_update
return w1, w0
np.random.permutation(x.shape[0]) => 주어진 데이터를 셔플해서 출력함
앞 함수와 바뀐 부분은 x, y를 샘플링해서 넣는다는 점 입니다.
w1, w0 = stochastic_gradient_descent_steps(x,y,iters=1000)
print('w1:', np.round(w1[0,0],3), 'w0:', np.round(w0[0,0],4))
y_pred = w1[0,0] * x + w0
print('편차제곱 평균:', np.round(get_cost(y,y_pred),4))
편차제곱 평균 값이 전체 x,y를 투입했을때와 큰 차이가 없습니다.
그러므로 계산 속도가 훨씬 빠른 미니배치 경사하강법을 많이 사용합니다.
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
from scipy import stats
from sklearn.datasets import load_boston
%matplotlib inline
boston = load_boston()
bostonDF = pd.DataFrame(boston.data, columns = boston.feature_names)
bostonDF['PRICE'] = boston.target
print('보스턴 데이터 세트 크기:', bostonDF.shape)
bostonDF.head()
사이킷런에 내장되어있는 보스턴 주택 데이터를 불러왔습니다.
bostonDF.info()
결측값은 없으며 모든 피처가 float 형 입니다.
fig, axs = plt.subplots(figsize=(16,8), ncols = 4, nrows = 2)
lm_features = ['RM','ZN', 'INDUS','NOX','AGE','PTRATIO','LSTAT','RAD']
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])
sns.regplot(x,y) => x,y 산점도와 함께 회귀직선을 그려줌.
plt.subplots(ncols = , nrows= ) 여러개의 그림을 그릴 수 있게 해줌.
RM과 LSTAT 변수가 가장 PRICE 변수와 연관성이 있어보입니다.
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score
y_target = bostonDF['PRICE']
x_data = bostonDF.drop(['PRICE'], axis = 1, inplace=False)
x_train, x_test, y_train, y_test = train_test_split(x_data, y_target, test_size = 0.3,
random_state = 156)
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)
print('mse :', np.round(mse,4), ', rmse :', np.round(rmse, 4))
print('결정계수:', np.round(r2_score(y_test, y_preds), 4))
모델을 어느정도 설명해 준 모습입니다.
print('절편 값:',lr.intercept_)
print('회귀 계수값:', np.round(lr.coef_,1))
coeff = pd.Series(data=np.round(lr.coef_, 1), index = x_data.columns)
coeff.sort_values(ascending=False)
변수 이름과 추정 회귀 계수를 맵핑 시킨 모습입니다.
NOX 변수의 계수 값이 크게 작아보입니다.
from sklearn.model_selection import cross_val_score
neg_mse_scores = cross_val_score(lr, x_data, y_target, scoring='neg_mean_squared_error', cv = 5)
rmse_scores = np.sqrt(-1 * neg_mse_scores)
avg_rmse = np.mean(rmse_scores)
print('mse scores', np.round(neg_mse_scores,2))
print('rmse scores', np.round(rmse_scores, 2))
print('평균 rmse score:', np.round(avg_rmse,2))
5개의 폴드 세트를 이용한 교차검증 입니다.
scoring = 'neg_mean_squared_error' 같은 경우 보통 모델 평가를 위한 값이 커야 좋은 값인데, mse 값은 작아야 좋습니다.
그러므로 음수를 붙여서 보정해준다고 생각하면 좋습니다.
다음에는 다항회귀, 릿지/라쏘 회귀 부분을 공부하겠습니다.