일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 체인지업후기
- 실제데이터활용
- 정보이득
- 군집화기법
- MultipleLinearRegression
- C4.5
- gradientdescent
- 선형모형
- 최소제곱법
- 경사하강법
- Adaboost
- 부스팅
- 사후 가지치기
- 아다부스트
- post pruning
- boosting
- LeastSquare
- pre pruning
- 선형회귀
- 의사결정나무
- 사전 가지치기
- 캘리포니아주택가격예측
- cost complexity pruning
- 회귀분석
- AdaBoostClassifier
- 부스팅기법
- LinearRegression
- 중선형회귀
- AdaBoostRegressor
- KNearestNeighbors
- Today
- Total
데이터 분석을 향한 발자취 남기기
4. 경사하강법을 이용한 선형회귀 본문
이전에 공부한 경사하강법을 이용해 선형회귀를 구현해보고자 한다.
그에 앞서, 사용한 데이터를 정리하고자 한다. 그후, 경사하강법을 통해 예측값들을 생성하고 이를 사이킷런의 선형회귀 모듈과 비교하고자 한다.
0. 캘리포니아 주택 가격 데이터
1. 경사하강법 적용
2. 예측결과 비교
0. 캘리포니아 주택 가격 데이터
모델 적용에 앞서, 데이터를 분석하고자 한다. 데이터는 사이킷런으로부터 쉽게 접근할 수 있으며, 모든 변수들이 연속형 변수로 구성되어있다. 데이터 분석의 목적은 캘리포니아 지역의 주택 가격을 예측하는 모델을 생성하는 것이다. 데이터는 아래와 같이 구성되어있으며 총 20,640개이다.
- 상관관계
상관관계 분석을 통해, 주택의 가격(MedHouseVal)은 소득(MedInc)과 강한 양의 상관관계를 가짐을 볼 수 있다. 또한, 설명변수들 중에서는 평균 침실 수(AveBedrms)가 평균 방의 수(AveRooms)와 강한 양의 상관관계를 보이며, 위도와 경도는 서로 매우 강한 음의 상관관계를 보인다.
- 변수들의 분포
각 피처들의 커널밀도함수를 그려보았을 때, 주택의 가격은 살짝 왼쪽으로 치우친 분포를 보임을 볼 수 있다. AveRooms, AveBedrms, AveOccup에서 평균 값보다 매우 큰 이상치의 영향을 받아 분포의 모양이 잘 보이지 않는다.
각 변수들의 박스 플랏을 살펴보면, 인구의 단위가 다른 변수들에 비해 단위가 매우 큼을 볼 수 있다. 이렇게, 피처들 간 단위차이가 크게 발생하면 대부분의 머신러닝 알고리즘들의 예측 성능을 감소시킨다. 또한, 경사하강법과 같은 추정기들의 계산이 매우 복잡해지고 수렴하는데 시간이 오래 걸린다. 따라서, 피처들에 대해 각각 표준화를 진행하고자 한다.
- 표준화
피처들의 단위를 조정하는 방법에는 크게 정규화와 표준화가 있는데, 이중에서 표준화를 사용하고자 한다. 표준화는 하나의 피처를 대상으로 이 피처 값의 평균과 표준편차를 이용해 처리한다.
$x_{i}$는 하나의 피처에 대한 $i$번째 데이터이고, $\mu, \sigma$는 해당 피처의 평균과 표준편차이다.
표준화를 통해, 모든 피처들(설명변수 + 반응변수)의 분포가 조정되었으며, 120 이하의 값들로 조정되었음을 알 수 있다.
그래프를 그리는 코드는 아래와 같다.
from sklearn.datasets import fetch_california_housing
import pandas as pd
import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt
dataset = fetch_california_housing()
# 데이터 불러오기
data = pd.DataFrame(dataset["data"], columns = dataset["feature_names"])
data.loc[:, "MedHouseVal"] = dataset.target
'''
상관관계 그래프
'''
# 대각선으로 쌓기 위한 좌표
mask = np.triu(np.ones_like(data.corr(), dtype=bool))
# 색깔
cmap = sns.diverging_palette(230, 20, as_cmap=True)
plt.figure(figsize = (7, 7))
sns.heatmap(data.corr(), mask=mask, cmap=cmap, vmin=-1, vmax = 1, center=0,
square=True, linewidths=.5, cbar_kws={"shrink": .5}, annot = True)
plt.title("Correlation", fontsize = 15, fontweight = "bold")
plt.tight_layout()
'''
커널밀도추정
'''
fig, ax = plt.subplots(3, 3, figsize = (10, 8))
k = 0
for i in range(3):
for j in range(3):
data.iloc[:, k].plot.kde(ax = ax[i][j], color = "black")
ax[i][j].set_xlabel(data.columns[k])
k+=1
plt.suptitle("Feature distribution", fontsize = 15, fontweight = "bold")
plt.tight_layout()
'''
박스플랏
'''
plt.figure(figsize = (10, 5))
data.boxplot(grid= False, showmeans=True,
meanprops={"marker":"o",
"markerfacecolor":"red",
"markeredgecolor":"red",
"markersize":"3"},
medianprops={"color":"black"},
color = "black")
plt.title("Feature boxplot", fontsize = 15, fontweight = "bold")
'''
데이터 정보
'''
data_info = pd.concat([data.min(), data.max(), data.mean(), data.std()], axis = 1)
'''
변수 표준화
'''
mean, std = data.mean(), data.std()
std_data = (data - mean)/std
plt.figure(figsize = (10, 5))
std_data.boxplot(grid= False, showmeans=True,
meanprops={"marker":"o",
"markerfacecolor":"red",
"markeredgecolor":"red",
"markersize":"3"},
medianprops={"color":"black"},
color = "black")
plt.title("Feature standardization boxplot", fontsize = 15, fontweight = "bold")
데이터의 분포를 살펴봄으로써, 전처리를 진행하였다.
이제, 준비된 데이터를 이용해 경사하강법을 진행하고자 한다.
1. 경사하강법 적용
여러 변수에 대해서 경사하강법을 적용할 때, 변수마다 편미분을 진행하고 파라미터를 각각 업데이트하면 어떻게 될까?
당연히 변수가 많아짐에 따라 코드는 복잡해질 것이다.
따라서, 여러 변수에 쉽게 적용할 수 있도록 행렬을 이용하고자 한다.
경사하강법 개념은 이쪽으로 ↓
https://footprints-toward-data-analysis.tistory.com/6
2. 경사하강법 (Gradient Descent)
회귀계수의 개수가 적으면, 고차원 방정식으로 비용함수가 최소가 되는 계수를 탐색할 순 있지만, 회귀계수의 개수가 많으면 고차원 방정식을 동원하더라도 풀기 어려운 문제가 존재한다. 비용
footprints-toward-data-analysis.tistory.com
경사하강법을 적용하기 위해 계수에 따라 편미분을 진행하면, $x_{i}$에 직접 곱해지는 회귀계수는 동일한 패턴을 띄지만, 절편은 다르게 계산한다. 이 경우 절편도 회귀계수와 같은 식으로 만들려면 ${x_{i}}$앞에 1을 새로 추가하면 된다!
절편은 1과 곱해지면서 원래 편미분 식으로 계산되고 나머지 회귀계수들은 해당하는 $x_{i}$와 곱해지면서 계산될 수 있는 것이다. 이 개념과 행렬 곱을 이용하면 8개의 피처들을 이용해서 주택 가격 예측은 쉽게 찾을 수 있다.
이때, 훈련집합과 테스트 집합은 7:3으로 구성하여 진행했다.
Train | Test | |
count | 14448 | 6192 |
total | 20640 |
# 가설함수
def hx_fuc(W, X):
return np.dot(X, W)
# 비용함수
def cost(h_x):
return 1/len(ytrain)*np.sum((ytrain-h_x)**2)
# 비용함수 W에 대한 편미분
def diff_coef(h_x, X):
return -2/len(ytrain)*np.dot((ytrain-h_x), grad_Xtrain)
# 초기설정(시작점, 학습률)
prev_W = np.zeros(Xtrain.shape[-1]+1)
# Xtrain 앞에 1 추가하기
grad_Xtrain = np.c_[np.ones(Xtrain.shape[0]), Xtrain]
prev_hx = hx_fuc(prev_W, grad_Xtrain) # 초기 가설함수
alpha = 0.01
iteration = 0
prev_W_info = []
while True:
iteration += 1
# 이전 변수를 이용해 업데이트
update_W = prev_W - alpha * diff_coef(prev_hx, grad_Xtrain)
update_hx = hx_fuc(update_W, grad_Xtrain)
# 업데이트 이전, 이후 비용함수
prev_cost, update_cost = cost(prev_hx), cost(update_hx)
prev_W_info.append(prev_W)
print(prev_W)
print(update_W)
# 업데이트 했을 때 비용이 더 크면 종료 -> learning rate 조정
if update_cost > prev_cost:
print("learning rate decrease")
break
# 비용함수 차이가 매우 작은 경우 종료
if abs(prev_cost - update_cost) < 1e-10:
print("find optimal values")
break
else:
prev_W = update_W
prev_hx = hx_fuc(update_W, grad_Xtrain)
target_mean, target_std = data.MedHouseVal.mean(), data.MedHouseVal.std()
# Xtest 앞에 1 추가하기
grad_Xtest = np.c_[np.ones(Xtest.shape[0]), Xtest]
grad_pred = np.dot(grad_Xtest, prev_W) * target_std + target_mean # 최종 예측값
print("Gradient Descent")
print("iter:", iteration)
print("intercept + coefficients:", prev_W)
주의할점
경사하강법은 변수의 scale(단위)에 영향을 받기 때문에 표준화를 하고 시작하지 않으면, 회귀계수를 탐색하는데 계산 및 시간이 오래 걸린다! (궁금하면 돌려보기..ㅎ)
따라서, 데이터를 다룰 때 바로 모델에 적용하지 않고 데이터 분석부터 차근차근 할 필요가 있다.
2. 예측결과 비교
완성된 경사하강법 알고리즘을 실제 사이킷런에서 구현해둔 Linear Regression과 비교하고자 한다.
- 회귀계수
경사하강법(GD)는 6485번의 반복을 통해 사이킷런의 Linear Regression 모듈과 매우 비슷한 회귀 결과를 보임을 알 수 있다.
- 성능
y값도 함께 표준화를 했기 때문에 실제 모델의 성능을 측정하기 위해서는 구한 예측값을 다시 실제값으로 변환해야한다. 성능 평가를 위해 회귀에서 많이 사용되는 MAE(Mean Absolute Error), RMSE(Root Mean Squared Error)를 사용한다.
**** 주의하기: 성능 평가 전 예측값이 잘 나왔는지 꼭 확인하기!! ****
위 그림을 보면 ytest인 주택 가격의 중앙값은 가격이므로 음수가 절대 발생할 수 없다!
하지만, 실제 모델들의 예측값들을 보면 음수로 예측하는 부분도 존재함을 알 수 있다.
이를 조심해야한다!!!!!
이러한 음수값은 다 0으로 처리해서 예측 성능을 계산한다.
그 결과, 두 모델은 서로 비슷한 성능을 보임을 알 수 있다.
약간의 차이는 경사하강법을 돌릴 때, 비용함수 값 차이가 1e-10보다 작아지면 멈추도록 설정해뒀기 때문에 발생하며, 이를 줄이면 사이킷런 선형회귀와 동일한 결과를 보일 것이다.
- 예측 비교
마지막으로 얼마나 예측을 잘 했는지 알아보기 위해서 예측 그래프를 그려보고자 한다. 그래프의 패턴을 잘 따라가는지 알기 위해 그래프를 그리는 것이므로 모든 점을 찍지 않고 100개의 예제에 대해서만 그래프를 나타냈다.
그래프를 통해 두 모델 모두 어느정도 주택 가격 중앙값의 패턴을 나타냄을 볼 수 있다.
오늘은 중선형회귀모델을 대상으로 경사하강법을 통해 구현해보았다.
다음 시간에는 로지스틱 회귀모델을 이용한 분류 문제를 해결해보려고 한다.
'손으로 직접 해보는 모델정리 > 단일 모델' 카테고리의 다른 글
6. KNN: K Nearest Neighbors (0) | 2023.05.12 |
---|---|
5. 경사하강법을 이용한 로지스틱 회귀 (0) | 2023.03.18 |
3. 로지스틱 회귀분석 (Logistic Regression) (0) | 2023.02.28 |
2. 경사하강법 (Gradient Descent) (0) | 2023.01.04 |
1. (다)중선형회귀분석 (Multiple Linear Regression Analysis) (0) | 2022.12.26 |