방정식을 배운 머신이는 몸무게와 키의 데이터를 획득했다. 일정하게 증가하는 패턴이 있어서 미리 몸무게를 알면 키를 알 수 있을 것이라고 생각했다.
weights = [87,81,82,92,90,61,86,66,69,69]
heights = [187,174,179,192,188,160,179,168,168,174]
키와 몸무게 간의 산점도

어떤 직선이 현재 데이터를 잘 '설명'한다고 할 수 있을까?

아무래도 빨간 그래프가 적절한 것 같다. 하지만 이렇게 대강 직선을 그리다보면 적절한 그래프를 찾기 어려울 것 같아 고민에 빠졌다.
머신이는 하나의 생각을 떠 올렸다. 바로 직선과 점의 간의 거리를 계산하는 것이다. 이를 Error 라고 정의하고 최소의 Error인 직선을 그리면 된다고 생각했다.


선형회귀식
: 가중치
: 편향 bias
두 수식의 의미는 같음. 회귀계수 혹은 가중치의 값을 알면 X가 주어졌을 때 Y를 알 수 있다.
에러 = 실제 데이터 - 예측 데이터 로 정의하기전체 모형에서 회귀선으로 설명할 수 있는 정도.
독립변수가 종속변수를 얼마나 잘 설명하는지 나타냄.

자주 쓰는 함수
- sklearn.linear_mode.LinearRegression
- coef_: 회귀 계수
- intercept_: 편향 (bias)
- fit: 데이터 학습
- predict: 데이터 예측
import sklearn
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
weights = [87, 81, 82, 92, 90, 61, 86, 66, 69, 69]
heights = [187, 174, 179, 192, 188, 160, 179, 168, 168, 174]
print(len(weights))
print(len(heights))
# 10
# 10
# dictionary 형태로 데이터 생성
body_df = pd.DataFrame({'height' : heights, 'weight' : weights})
body_df.head(3)

# weight와 height간의 산점도(scatter plot)
sns.scatterplot( data = body_df, x = 'weight', y = 'height')
plt.title('Weight vs Height')
plt.xlabel('weight(kg)')
plt.ylabel('Height (cm)')
plt.show()

from sklearn.linear_model import LinearRegression
model_lr = LinearRegression()
# 입력값 미리 정의
X = body_df[['weight']]
y = body_df[['height']]
# DataFrame[]: Series(데이터 프레임의 컬럼)
# DataFrame[[]]: DataFrame
# 데이터 훈련
model_lr.fit(X = X, y = y)
# 가중치(w1)
print(model_lr.coef_)
# 편향(bias, w0)
print(model_lr.intercept_)
# [[0.86251245]]
# [109.36527488]
w1 = model_lr.coef_[0][0]
w0 = model_lr.intercept_[0]
print('y = {}x + {}'.format(w1.round(2),w0.round(2)))
# y = 0.86x + 109.37
y(height)는 x(몸무게)에 0.86을 곱한뒤 109.37을 더하면 된다.
body_df['pred'] = body_df['weight'] * w1 + w0
body_df.head(3)

body_df['error'] = body_df['height'] - body_df['pred']
body_df['error^2'] = body_df['error']*body_df['error']

body_df['error^2'].sum()/len(body_df)
# 10.152939045376309
sns.scatterplot(data = body_df, x = 'weight', y = 'height')
sns.lineplot(data = body_df, x = 'weight', y = 'pred', color = 'red')

from sklearn.metrics import mean_squared_error, r2_score
# 평가함수는 공통적으로 정답(실제 true), 예측값(pred) 입력
y_true = body_df['height']
y_pred = body_df['pred']
# MSE
mean_squared_error(y_true, y_pred)
# 10.152939045376309
# R square
r2_score(y_true, y_pred)
# 0.8899887415172141
y_pred2 = model_lr.predict(body_df[['weight']])
y_pred2
# 결과
array([[184.40385835],
[179.22878362],
[180.09129608],
[188.71642061],
[186.99139571],
[161.97853455],
[183.54134589],
[166.29109682],
[168.87863418],
[168.87863418]])
# 확인
mean_squared_error(y_true,y_pred2)
# 10.152939045376318
tips_df = sns.load_dataset('tips')
tips_df.head(3)

sns.scatterplot(data = tips_df, x = 'total_bill', y= 'tip')

# 학습
model_lr2 = LinearRegression()
X = tips_df[['total_bill']]
y = tips_df[['tip']]
model_lr2.fit(X,y)
# 확인
# y(tip) = w1*x(total_bill) + w0
w1_tip = model_lr2.coef_[0][0]
w0_tip = model_lr2.intercept_[0]
print('y = {}x + {}'.format(w1_tip.round(2), w0_tip.round(2)))
# y = 0.11x + 0.92
y_true_tip = tips_df['tip']
y_pred_tip = model_lr2.predict(tips_df[['total_bill']])
# MSE
mean_squared_error(y_true_tip, y_pred_tip)
# 1.036019442011377
# R square
r2_score(y_true_tip, y_pred_tip)
# 0.45661658635167657
# 데이터프레임에 예측값 추가
tips_df['pred'] = y_pred_tip
sns.scatterplot(data = tips_df, x = 'total_bill', y= 'tip')
sns.lineplot(data = tips_df, x = 'total_bill', y = 'pred', color = 'red')

지금까지는 X와 Y간의 데이터에 아주 간단한 단순회귀분석에 대해서만 배웠지만 실제의 데이터들은 비선형적 관계를 가지는 경우가 많습니다. 이를 위해서 X변수를 추가 할 수도, 변형할 수 도 있습니다.


머신이는 데이터 선형회귀를 훈련 시켰지만 성능이 별로 좋지 않다는 것을 알게 되었습니다. 그래서 성별과 같은 다른 데이터를 사용하고 싶어졌습니다. 그런데 문제는 성별데이터는 문자형이여서 숫자로 표현할 방법이 필요해졌습니다.
tips_df.head(3)

# Female 0, Male 1
def get_sex(x):
if x == 'Female':
return 0
else:
return 1
#apply method는 매 행을 특정한 함수를 적용한다.
tips_df['sex_en'] = tips_df['sex'].apply(get_sex)
tips_df.head(3)

model_lr3 = LinearRegression()
X = tips_df[['total_bill','sex_en']]
y = tips_df[['tip']]
model_lr3.fit(X,y)
y_pred_tip2 = model_lr3.predict(X)
y_pred_tip2[:5]
# 결과
array([[2.72117624],
[1.99477235],
[3.1176016 ],
[3.39857199],
[3.52094215]])
# 단순선형회귀 mse: X변수가 전체 금액
# 다중선형회귀 mse: X변수가 전체 금액, 성별
# MSE
print('단순선형회귀', mean_squared_error(y_true_tip, y_pred_tip))
print('다중선형회귀', mean_squared_error(y_true_tip, y_pred_tip2))
# 단순선형회귀 1.036019442011377
# 다중선형회귀 1.0358604137213614
# R square
print('단순선형회귀', r2_score(y_true_tip, y_pred_tip))
print('다중선형회귀', r2_score(y_true_tip, y_pred_tip2))
# 단순선형회귀 0.45661658635167657
# 다중선형회귀 0.45669999534149974
ex)

- 귀무가설 : 는 0이다. 즉, Y에 영향이 없다.
- 대립가설: 는 0이 아니다.


변수가 많아지면 서로 연관이 있는 경우가 많다. 이처럼 회귀분석에서 독립변수(X)간의 강한 상관관계가 나타나는 것을 다중공선성(Multicolinearity)문제라고 한다.


