Ch5 Linear Regression 36-43 (머신러닝 10-11)

김민지·2023년 5월 22일
0

Part 09. 머신러닝

목록 보기
4/4
  1. Basic of Regression
  • 지도학습1 - 분류(Classification) -> 출력이 0 혹은 1

  • 지도학습2 - 회귀(Regression) -> 출력이 연속된 값(continuous value)임

  • 비지도학습1 - 군집

  • 비지도학습2 - 차원 축소

  • 회귀 : ex) 주택의 넓이와 가격이라는 데이터를 가지고 주택크기가 주어졌을 때 주택가격을 예측하기

  • 선형회귀(Linear Regression) : 입력변수(특징) x가 하나인 경우, 선형회귀는 주어진 학습데이터와 가장 잘 맞는 Hypothesis 함수 h를 찾는 문제가 됨

  • OLS (Ordinary Linear Least Square)

!pip install statsmodels
import pandas as pd

data = {'x' : [1., 2., 3., 4., 5.], 'y' : [1., 3., 4., 6., 5.]}
df = pd.DataFrame(data)
df
  • 가설 세우기
import statsmodels.formula.api as smf

lm_model = smf.ols(formula='y ~ x', data=df).fit()
  • 결과
lm_model.params

-> 출력결과

Intercept    0.5
x            1.1
dtype: float64
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
sns.lmplot(x='x', y='y', data=df);
  • 잔차 평가 (residue)
    -> 잔차는 평균이 0인 정규분포를 따르는 것이어야 함
    -> 잔차 평가는 잔차의 평균이 0이고 정규분포를 따르는지 확인

  • 잔차 확인

resid = lm_model.resid
resid
  • 결정계수 (R-Squared)
    -> y_hat은 예측된 값
    -> 예측 값과 실제 값(y)이 일치하면 결정계수는 1이 됨
    -> 즉 결정계수가 높을수록 좋은 모델

  • numpy로 직접 결정계수 계산하기

import numpy as np

mu = np.mean(df.y)
y = df.y

y_hat = lm_model.predict()
np.sum((y_hat - mu)**2 / np.sum((y - mu)**2))
  • 간단하게 결정계수 구하는 방법
lm_model.rsquared
  • 잔차의 분포도 확인
sns.distplot(resid, color='black');
  1. 통계적 회귀
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
data_url = "https://raw.githubusercontent.com/PinkWink/ML_tutorial/master/dataset/ecommerce.csv"
data = pd.read_csv(data_url)
data.columns
  • 필요없는 컬럼 삭제
data.drop(['Email', 'Address', 'Avatar'], axis=1, inplace=True)
data.info()
  • 컬럼별 boxplot
plt.figure(figsize=(12, 6))
sns.boxplot(data=data);
  • 특성들만 다시 boxplot
plt.figure(figsize=(12, 6))
sns.boxplot(data=data.iloc[:, :-1]);
  • Label 값에 대한 boxplot
plt.figure(figsize=(12, 6))
sns.boxplot(data=data['Yearly Amount Spent']);
  • pairplot으로 경향 확인
plt.figure(figsize=(12, 6))
sns.pairplot(data=data);

-> 큰 상관관계를 보이는 것은 'Length of Membership'와 'Yearly Amount Spent'

  • lmplot으로 확인
plt.figure(figsize=(12, 6))
sns.lmplot(x='Length of Membership', y='Yearly Amount Spent', data=data);
  • 상관이 높은 멤버쉽 유지기간만 가지고 통계적 회귀
import statsmodels.api as sm

X = data['Length of Membership']
y = data['Yearly Amount Spent']
lm = sm.OLS(y, X).fit()
lm.summary()
  • 수치의 의미 해석하기
    1) R-squared : 모형 적합도, y의 분산을 각각의 변수들이 약 99.8%로 설명할 수 있음
    2) Adj.R-squared : 독립변수가 여러 개인 다중회귀분석에서 사용
    3) Prob.F-Statistic : 회귀모형에 대한 통계적 유의미성 검정. 이 값이 0.05 이하라면 모집단에서도 의미가 있다고 볼 수 있음.
  • 회귀 모델 그리기
pred = lm.predict(X)

sns.scatterplot(x=X, y=y)
plt.plot(X, pred, 'r', ls='dashed', lw=3)
sns.scatterplot(x=y, y=pred)
plt.plot([min(y), max(y)], [min(y), max(y)], 'r', ls='dashed', lw=3);
plt.plot([0, max(y)], [0, max(y)], 'b', ls='dashed', lw=3)
plt.axis([0, max(y), 0, max(y)])

-> 상수항이 없음

  • 상수항 넣어주기
X = np.c_[X, [1]*len(X)]
X[:5]
  • 다시 모델 fit
lm = sm.OLS(y, X).fit()
lm.summary()
  • 선형 회귀 결과
pred = lm.predict(X)

sns.scatterplot(x=X[:, 0], y=y)
plt.plot(X[:, 0], pred, 'r', ls='dashed', lw=3)
  • 참 값 vs 예측 값
pred = lm.predict(X)

sns.scatterplot(x=y, y=pred)
plt.plot([min(y), max(y)], [min(y), max(y)], 'r', ls='dashed', lw=3);
  • 이번에는 데이터 분리 후
from sklearn.model_selection import train_test_split

X = data.drop('Yearly Amount Spent', axis=1)
y = data['Yearly Amount Spent']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=13)
  • 네 개 컬럼 모두를 변수로 보고 회귀
import statsmodels.api as sm

lm = sm.OLS(y_train, X_train).fit()
lm.summary()
  • 참 값 vs 예측 값
pred = lm.predict(X_test)

sns.scatterplot(x=y_test, y=pred)
plt.plot([min(y_test), max(y_test)], [min(y_test), max(y_test)], 'r', ls='dashed', lw=3);
  1. Cost Function
  • 만약 주택의 넓이와 가격이라는 데이터가 있고, 주택가격을 예측한다면,
    -> 학습 데이터 각각에 정답(주택 가격)이 주어져 있으므로 '지도학습(Supervised Learning)'이며,
    -> 주택 가격을 연속된 값으로 예측하는 것이므로 '회귀(Regression)' 문제임
  • 머신러닝 모델 만들기
  • 입력 변수(특징) x가 하나인 경우, 선형 회귀(Linear Regression) 문제는 주어진 학습데이터와 가장 잘 맞는 Hypothesis 함수 h를 찾는 문제가 됨.
  • 직선상에 있지 않은 세 점을 직선으로 표현하기
    -> 직선으로만 표현한다면, 그나마 각 점(데이터)과 직선(구하고자 하는 모델) 사이의 에러가 제일 작도록 만들 것
  • 실제 데이터(점 세 개)로 모델(h) 구하기
    -> 먼저 각각의 에러를 구하고, 각각의 에러를 제곱하고(제곱하는 이유는 부호를 없애기 위함. 절대값을 사용하는 경우도 있음), 평균을 구함 -> Cost Function(에러를 표현하는 도구)
  • Cost Function을 최솟값을 찾는 것이 중요함
import numpy as np

np.poly1d([2, -1])**2 + np.poly1d([3, -5])**2 + np.poly1d([5, -6])**2

-> 출력결과 : poly1d([ 38, -94, 62])
-> poly1d : 다항식 표현하는 도구, 다항식 계산에 용이함

  • 최솟값 구하기
!pip install sympy
import sympy as sym

theta = sym.Symbol('theta')
diff_th = sym.diff(38*theta**2 - 94*theta + 62, theta)
diff_th
  • 실제 데이터는 너무 복잡해서 손으로 풀기 어려움. 데이터의 특징(feature)이 여러 개가 존재해서 평면상의 방정식이 아니라 다차원에서 고민해야 할 때가 많음.

  • Cost Function의 최솟값을 찾기 위해서 특단의 대책이 필요
    -> Gradient Descent

  • Gradient Descent
    -> 미분을 통해서 Cost Function의 최솟값을 찾음

  • Learning Rate(학습률)

  1. 예제 (Boston 집값 예측)
from sklearn.datasets import load_boston

boston = load_boston()
print(boston.DESCR)
  • 각 특성 살펴보기
[each for each in boston.feature_names]
  • 데이터 파악을 위해 pandas로 정리
import pandas as pd

boston_pd = pd.DataFrame(boston.data, columns=boston.feature_names)
boston_pd['Price'] = boston.target   # 집 값

boston_pd.head()
  • Price에 대한 histogram
import plotly.express as px

fig = px.histogram(boston_pd, x='PRICE')
fig.show()
  • 각 특성별 상관계수 확인 (히트맵)
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

corr_mat = boston_pd.corr().round(1)
sns.set(rc={'figure.figsize' : (10, 8)})
sns.heatmap(data=corr_mat, annot_True, cmap='bwr');

-> Price와 방의 수(RM), 저소득층 인구(LSTAT)와 높은 상관관계가 보임

  • RM과 LSTAT와 PRICE의 관계에 대해 관찰해보기
sns.set_style('darkgrid')
sns.set(rc={'figure.figsize' : (12, 6)})

fig, ax = plt.subplots(ncols=2)
sns.regplot(x='RM', y='PRICE', data=boston_pd, ax=ax[0])
sns.regplot(x='LSTAT', y='PRICE', data=boston_pd, ax=ax[1]);

-> 저소득층 인구가 낮을수록, 방의 개수가 많을수록 집 값이 높아짐
-> 두 특성이 정말 집 값에 유의미한 영향을 주는지 확인해볼 필요가 있음

  • 데이터 나누기
from sklearn.model_selection import train_test_split

X = boston_pd.drop('PRICE', axis=1)
y = boston_pd['PRICE']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=13)
  • LinearRegression 사용해서 학습
from sklearn.linear_model import LinearRegression

reg = LinearRegression()
reg.fit(X_train, y_train)
  • RMS로 모델평가
import numpy as np
from sklearn.metrics import mean_squared_error

pred_tr = reg.predict(X_train)
pred_test = reg.predict(X_test)

rmse_tr = (np.sqrt(mean_squared_error(y_train, pred_tr)))
rmse_test = (np.sqrt(mean_squared_error(y_test, pred_test)))

print('RMSE of Train Data : ', rmse_tr)
print('RMSE of Test Data : ', rmse_test)
  • 성능 확인 (시각화)
plt.scatter(y_test, pred_test)
plt.xlabel('Actual House Prices ($1000)')
plt.ylabel('Predicted Prices')
plt.title('Real vs Predicted')
plt.plot([0,50], [0,50], 'r')
plt.show()
  • LSTAT 사용이 맞는가? 한번 빼 봄
X = boston_pd.drop(['PRICE', 'LSTAT'], axis=1)
y = boston_pd['PRICE']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=13)

reg = LinearRegression()
reg.fit(X_train, y_train)
pred_tr = reg.predict(X_train)
pred_test = reg.predict(X_test)

rmse_tr = (np.sqrt(mean_squared_error(y_train, pred_tr)))
rmse_test = (np.sqrt(mean_squared_error(y_test, pred_test)))

print('RMSE of Train Data : ', rmse_tr)
print('RMSE of Test Data : ', rmse_test)  # 높아짐

-> 성능이 나빠짐 but LSTAT를 빼도 될지 안될지는 더 고민해봐야 함

plt.scatter(y_test, pred_test)
plt.xlabel('Actual House Prices ($1000)')
plt.ylabel('Predicted Prices')
plt.title('Real vs Predicted')
plt.plot([0,48], [0,48], 'r')
plt.show()

<제로베이스 데이터 취업 스쿨>

0개의 댓글