Fundamental 05
Fundamental 05
1. 맥북의 중고가 맞춰보기
데이터 확인
import pandas as pd
macbook = pd.read_csv('~/aiffel/bike_regression/data/macbook.csv')
print(macbook.shape)
macbook.head()
(80, 2)
| used_years | price | |
|---|---|---|
| 0 | 2.65 | 175 |
| 1 | 3.80 | 63 |
| 2 | 0.95 | 273 |
| 3 | 4.50 | 133 |
| 4 | 4.45 | 106 |
data : macbook.csv (실습을 위한 간의 데이터)
shape : 데이터는 used_years(사용한 연도), price(가격) 두 개의 col을 갖는 80개의 데이터 셋이다.
데이터 시각화
import matplotlib.pyplot as plt
# 실행한 브라우저에서 바로 그림을 볼 수 있게 해줌
%matplotlib inline
%config InlineBackend.figure_format = 'retina' # 더 높은 해상도로 출력한다.
plt.scatter(macbook['used_years'], macbook['price'])
plt.show()

x축(사용한 연도)으로 갈 수록 y축(가격)이 내려간다.
상관관계

상관관계와 상관계수는 두 변수 간의 패턴을 나타내는 것이 아닌, 각 값의 증가 또는 감소에 대한 관계만을 나타낸다.
이러한 상관관계를 볼 때 macbook데이터는 음의 상관관계를 갖는다고 할 수 있다.
상관계수 구해보기
import numpy as np
# np.corrcoef(x, y)를 사용합니다.
np.corrcoef(macbook['used_years'], macbook['price'])
array([[ 1. , -0.78972238],
[-0.78972238, 1. ]])
(0,0), (1,1)은 자기자신의 상관관계를 나타내고 나머지는 둘의 상관관게를 나타낸다.
-0.78972238로 큰 음의 상관관계를 나타내는 것을 볼 수 있다.
모델 구현하기
x = macbook["used_years"].values
y = macbook["price"].values
def model(x, w, b):
y = w * x + b
return y
model(5, 2, 1)
11
# x축, y축 그리기
plt.axvline(x=0, c='black')
plt.axhline(y=0, c='black')
# y = wx + b 일차함수 그리기
x = np.linspace(0, 8, 9)
y = model(x, w=-20, b=140) # y = -20x + 140
plt.plot(y)
# 나의 (x, y) 점 찍기
x_data = [2, 5, 6]
y_data = [100, 40, 20]
plt.scatter(x_data, y_data, c='r', s=50)
plt.show()

지금 구현한 모델은 일차함수로 구현하였다. 하지만 우리의 데이터는 일차함수처럼 일직선 상에 놓이지 않는다. 그렇기 때문에 가장 오차가 적은 일차함수를 구현해야한다.
정답과 예측값 간의 차이
w = 3.1
b = 2.3
x = np.linspace(0, 5, 6)
y = model(x, w, b) # y = 3.1x + 2.3
x = macbook["used_years"].values
prediction = model(x, w, b) # 현재 w = 3.1, b = 2.3
macbook['prediction'] = prediction
macbook['error'] = macbook['price'] - macbook['prediction']
macbook.head()
| used_years | price | prediction | error | |
|---|---|---|---|---|
| 0 | 2.65 | 175 | 10.515 | 164.485 |
| 1 | 3.80 | 63 | 14.080 | 48.920 |
| 2 | 0.95 | 273 | 5.245 | 267.755 |
| 3 | 4.50 | 133 | 16.250 | 116.750 |
| 4 | 4.45 | 106 | 16.095 | 89.905 |
우리는 오차를 줄이기 위해 몇 가지의 지표를 사용할 수 있는데 이것은 정답 라벨에서 우리가 예측한 값들을 뺀값을 사용하는 방법이다.
모델이 얼마나 틀렸는지 평가하는 지표에는 MAE, MSE, RMSE, R-squared등이 있는데 우리는 RMSE를 사용할 것이다.
def RMSE(a, b):
mse = ((a - b) ** 2).mean() # 두 값의 차이의 제곱의 평균
rmse = mse ** 0.5 # MSE의 제곱근
return rmse
x = macbook["used_years"].values
y = macbook["price"].values
predictions = model(x, w, b)
rmse = RMSE(predictions, y)
rmse
188.81322969819274
모델이 너무 부정확하기 때문에 rmse값이 매우 크게 나온것을 확인할 수 있다.
손실 함수
def loss(x, w, b, y):
predictions = model(x, w, b)
L = RMSE(predictions, y)
return L
모델의 예측값과 정답값에 대한 차이를 계산하는 함수를 손실함수라고 한다.
기울기와 경사하강법(Gradient Descent)
손실 함수를 줄이기 위해 우리가 바꿀 수 있는 변수는 w, b이 두 개뿐이다.



왼쪽 점은 자기 자신의 위치보다 오른쪽으로 갈수록 손실함수값이 점점 작아지기 때문에 그 점에서 그린 접선은 오른쪽 아래로 향하는 방향 이고, 그 기울기는 음수 입니다.
오른쪽 점은 자기 자신의 위치보다 왼쪽으로 갈수록 손실함수값이 점점 작아지기 때문에 그 점에서 그린 접선은 왼쪽 아래로 향하는 방향이고, 그 기울기는 양수 입니다.
def gradient(x, w, b, y):
dw = (loss(x, w + 0.0001, b, y) - loss(x, w, b, y)) / 0.0001
db = (loss(x, w, b + 0.0001, y) - loss(x, w, b, y)) / 0.0001
return dw, db
하이퍼파라미터
하이퍼파라미터란 학습률과 같이 모델이 스스로 학습해나가는 파라미터가 아니라, 사람이 직접 사전에 정하고 시작해야하는 파라미터이다.
LEARNING_RATE = 1
모델 최적화
학습을 하면서 손실 함수의 값을 저장할 배열 선언
losses = []
학습을 진행하면서 loss구하기
for i in range(1, 2001):
dw, db = gradient(x, w, b, y) # 3, 4번: 모델이 prediction을 예측하고, 손실함수값을 계산함과 동시에 기울기 계산
w -= LEARNING_RATE * dw # 5번: w = w - η * dw 로 업데이트
b -= LEARNING_RATE * db # 5번: b = b - η * db 로 업데이트
L = loss(x, w, b, y) # 현재의 loss 값 계산
losses.append(L) # loss 값 기록
if i % 100 == 0:
print('Iteration %d : Loss %0.4f' % (i, L))
Iteration 100 : Loss 107.8708
Iteration 200 : Loss 94.4397
Iteration 300 : Loss 81.7335
Iteration 400 : Loss 70.0698
Iteration 500 : Loss 59.8849
Iteration 600 : Loss 51.6766
Iteration 700 : Loss 45.7883
Iteration 800 : Loss 42.1201
Iteration 900 : Loss 40.1217
Iteration 1000 : Loss 39.1354
Iteration 1100 : Loss 38.6763
Iteration 1200 : Loss 38.4689
Iteration 1300 : Loss 38.3766
Iteration 1400 : Loss 38.3358
Iteration 1500 : Loss 38.3178
Iteration 1600 : Loss 38.3098
Iteration 1700 : Loss 38.3063
Iteration 1800 : Loss 38.3048
Iteration 1900 : Loss 38.3041
Iteration 2000 : Loss 38.3038
그래프 그리기
plt.plot(losses)
plt.show()

그래프를 보니 학습을 진행할 수록 오차가 줄어드는 것을 볼 수 있다.
w, b
(-44.92802735596856, 293.082887486003)
# 모델에 넣을 x 값들 준비
x = np.linspace(0, 5, 6)
# x, w, b를 모델에 넣어 y값 출력
y = model(x, w, b)
# 일차함수 y 그리기
plt.plot(y, c="r")
# 원본 데이터 점찍기
plt.scatter(macbook['used_years'], macbook['price'])
plt.show()

Unseen data에 적용하기
# 새로운 데이터 macbook_test 가져오기
test = pd.read_csv("~/aiffel/bike_regression/data/macbook_test.csv")
print(test.shape)
test.head()
(20, 2)
| used_years | price | |
|---|---|---|
| 0 | 1.20 | 203 |
| 1 | 1.85 | 206 |
| 2 | 2.40 | 191 |
| 3 | 2.85 | 164 |
| 4 | 3.05 | 176 |
test_x = test['used_years'].values
test_y = test['price'].values
prediction = model(test_x, w, b)
test['prediction'] = prediction
test
| used_years | price | prediction | |
|---|---|---|---|
| 0 | 1.20 | 203 | 239.169255 |
| 1 | 1.85 | 206 | 209.966037 |
| 2 | 2.40 | 191 | 185.255622 |
| 3 | 2.85 | 164 | 165.038010 |
| 4 | 3.05 | 176 | 156.052404 |
| 5 | 3.35 | 136 | 142.573996 |
| 6 | 2.55 | 133 | 178.516418 |
| 7 | 2.60 | 181 | 176.270016 |
| 8 | 2.50 | 181 | 180.762819 |
| 9 | 3.10 | 86 | 153.806003 |
| 10 | 2.70 | 171 | 171.777214 |
| 11 | 3.40 | 253 | 140.327594 |
| 12 | 1.30 | 263 | 234.676452 |
| 13 | 1.80 | 129 | 212.212438 |
| 14 | 3.10 | 135 | 153.806003 |
| 15 | 1.55 | 236 | 223.444445 |
| 16 | 1.80 | 206 | 212.212438 |
| 17 | 3.55 | 203 | 133.588390 |
| 18 | 3.40 | 96 | 140.327594 |
| 19 | 2.50 | 115 | 180.762819 |
test['error'] = test['price'] - test['prediction']
test
| used_years | price | prediction | error | |
|---|---|---|---|---|
| 0 | 1.20 | 203 | 239.169255 | -36.169255 |
| 1 | 1.85 | 206 | 209.966037 | -3.966037 |
| 2 | 2.40 | 191 | 185.255622 | 5.744378 |
| 3 | 2.85 | 164 | 165.038010 | -1.038010 |
| 4 | 3.05 | 176 | 156.052404 | 19.947596 |
| 5 | 3.35 | 136 | 142.573996 | -6.573996 |
| 6 | 2.55 | 133 | 178.516418 | -45.516418 |
| 7 | 2.60 | 181 | 176.270016 | 4.729984 |
| 8 | 2.50 | 181 | 180.762819 | 0.237181 |
| 9 | 3.10 | 86 | 153.806003 | -67.806003 |
| 10 | 2.70 | 171 | 171.777214 | -0.777214 |
| 11 | 3.40 | 253 | 140.327594 | 112.672406 |
| 12 | 1.30 | 263 | 234.676452 | 28.323548 |
| 13 | 1.80 | 129 | 212.212438 | -83.212438 |
| 14 | 3.10 | 135 | 153.806003 | -18.806003 |
| 15 | 1.55 | 236 | 223.444445 | 12.555555 |
| 16 | 1.80 | 206 | 212.212438 | -6.212438 |
| 17 | 3.55 | 203 | 133.588390 | 69.411610 |
| 18 | 3.40 | 96 | 140.327594 | -44.327594 |
| 19 | 2.50 | 115 | 180.762819 | -65.762819 |
rmse = ((test['error'] ** 2).sum() / len(test)) ** 0.5
rmse
45.039281182770374
# 모델 일차함수 그리기
x = np.linspace(0, 5, 6)
y = model(x, w, b)
plt.plot(y, c="r")
# 실제 데이터 값
plt.scatter(test['used_years'], test['price'])
# 모델이 예측한 값
plt.scatter(test['used_years'], test['prediction'])
plt.show()

2. 손님의 성별, 수, 총 결제 금액 등으로 내가 받을 팁 예측하기
데이터 확인하기
import seaborn as sns
tips = sns.load_dataset("tips")
print(tips.shape)
tips.head()
(244, 7)
| total_bill | tip | sex | smoker | day | time | size | |
|---|---|---|---|---|---|---|---|
| 0 | 16.99 | 1.01 | Female | No | Sun | Dinner | 2 |
| 1 | 10.34 | 1.66 | Male | No | Sun | Dinner | 3 |
| 2 | 21.01 | 3.50 | Male | No | Sun | Dinner | 3 |
| 3 | 23.68 | 3.31 | Male | No | Sun | Dinner | 2 |
| 4 | 24.59 | 3.61 | Female | No | Sun | Dinner | 4 |
# 데이터를 다루기 위해 문자열을 실수값으로 변환하기
import pandas as pd
tips = pd.get_dummies(tips, columns=['sex', 'smoker', 'day', 'time'])
tips.head()
| total_bill | tip | size | sex_Male | sex_Female | smoker_Yes | smoker_No | day_Thur | day_Fri | day_Sat | day_Sun | time_Lunch | time_Dinner | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 16.99 | 1.01 | 2 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 1 |
| 1 | 10.34 | 1.66 | 3 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 1 |
| 2 | 21.01 | 3.50 | 3 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 1 |
| 3 | 23.68 | 3.31 | 2 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 1 |
| 4 | 24.59 | 3.61 | 4 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 1 |
tips = tips[['total_bill', 'size', 'sex_Male', 'sex_Female', 'smoker_Yes', 'smoker_No',
'day_Thur', 'day_Fri', 'day_Sat', 'day_Sun', 'time_Lunch', 'time_Dinner', 'tip']]
tips.head()
| total_bill | size | sex_Male | sex_Female | smoker_Yes | smoker_No | day_Thur | day_Fri | day_Sat | day_Sun | time_Lunch | time_Dinner | tip | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 16.99 | 2 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 1.01 |
| 1 | 10.34 | 3 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 1.66 |
| 2 | 21.01 | 3 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 3.50 |
| 3 | 23.68 | 2 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 3.31 |
| 4 | 24.59 | 4 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 3.61 |
모델 구현하기
train, test 데이터셋 준비
X = tips[['total_bill', 'size', 'sex_Male', 'sex_Female', 'smoker_Yes', 'smoker_No',
'day_Thur', 'day_Fri', 'day_Sat', 'day_Sun', 'time_Lunch', 'time_Dinner']].values
y = tips['tip'].values
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
print(X_train.shape, y_train.shape)
print(X_test.shape, y_test.shape)
(195, 12) (195,)
(49, 12) (49,)
가중치, 편향 초기화
import numpy as np
W = np.random.rand(12)
b = np.random.rand()
모델 구현
def model(X, W, b):
predictions = 0
for i in range(12):
predictions += X[:, i] * W[i]
predictions += b
return predictions
손실 함수 구현
def MSE(a, b):
mse = ((a - b) ** 2).mean() # 두 값의 차이의 제곱의 평균
return mse
def loss(X, W, b, y):
predictions = model(X, W, b)
L = MSE(predictions, y)
return L
기울기
def gradient(X, W, b, y):
# N은 가중치의 개수
N = len(W)
# y_pred 준비
y_pred = model(X, W, b)
# 공식에 맞게 gradient 계산
dW = 1/N * 2 * X.T.dot(y_pred - y)
# b의 gradient 계산
db = 2 * (y_pred - y).mean()
return dW, db
dW, db = gradient(X, W, b, y)
print("dW:", dW)
print("db:", db)
dW: [14428.59079778 1751.21974468 417.01234212 208.91814472
251.36926445 374.56122239 140.45304262 42.98158454
229.92678479 212.56907491 150.9676628 474.96282405]
db: 30.78346656616838
모델 학습
LEARNING_RATE = 0.0001
losses = []
for i in range(1, 1001):
dW, db = gradient(X_train, W, b, y_train)
W -= LEARNING_RATE * dW
b -= LEARNING_RATE * db
L = loss(X_train, W, b, y_train)
losses.append(L)
if i % 10 == 0:
print('Iteration %d : Loss %0.4f' % (i, L))
Iteration 10 : Loss 2.4343
Iteration 20 : Loss 2.3668
Iteration 30 : Loss 2.3141
Iteration 40 : Loss 2.2643
Iteration 50 : Loss 2.2173
Iteration 60 : Loss 2.1728
Iteration 70 : Loss 2.1308
Iteration 80 : Loss 2.0911
Iteration 90 : Loss 2.0535
Iteration 100 : Loss 2.0180
Iteration 110 : Loss 1.9843
Iteration 120 : Loss 1.9524
Iteration 130 : Loss 1.9222
Iteration 140 : Loss 1.8935
Iteration 150 : Loss 1.8663
Iteration 160 : Loss 1.8404
Iteration 170 : Loss 1.8159
Iteration 180 : Loss 1.7926
Iteration 190 : Loss 1.7704
Iteration 200 : Loss 1.7494
Iteration 210 : Loss 1.7293
Iteration 220 : Loss 1.7102
Iteration 230 : Loss 1.6920
Iteration 240 : Loss 1.6746
Iteration 250 : Loss 1.6581
Iteration 260 : Loss 1.6423
Iteration 270 : Loss 1.6272
Iteration 280 : Loss 1.6128
Iteration 290 : Loss 1.5990
Iteration 300 : Loss 1.5858
Iteration 310 : Loss 1.5732
Iteration 320 : Loss 1.5611
Iteration 330 : Loss 1.5495
Iteration 340 : Loss 1.5384
Iteration 350 : Loss 1.5277
Iteration 360 : Loss 1.5175
Iteration 370 : Loss 1.5077
Iteration 380 : Loss 1.4982
Iteration 390 : Loss 1.4891
Iteration 400 : Loss 1.4804
Iteration 410 : Loss 1.4720
Iteration 420 : Loss 1.4639
Iteration 430 : Loss 1.4561
Iteration 440 : Loss 1.4486
Iteration 450 : Loss 1.4413
Iteration 460 : Loss 1.4343
Iteration 470 : Loss 1.4275
Iteration 480 : Loss 1.4210
Iteration 490 : Loss 1.4146
Iteration 500 : Loss 1.4085
Iteration 510 : Loss 1.4026
Iteration 520 : Loss 1.3969
Iteration 530 : Loss 1.3913
Iteration 540 : Loss 1.3859
Iteration 550 : Loss 1.3807
Iteration 560 : Loss 1.3756
Iteration 570 : Loss 1.3707
Iteration 580 : Loss 1.3659
Iteration 590 : Loss 1.3613
Iteration 600 : Loss 1.3568
Iteration 610 : Loss 1.3524
Iteration 620 : Loss 1.3481
Iteration 630 : Loss 1.3440
Iteration 640 : Loss 1.3399
Iteration 650 : Loss 1.3360
Iteration 660 : Loss 1.3322
Iteration 670 : Loss 1.3284
Iteration 680 : Loss 1.3248
Iteration 690 : Loss 1.3213
Iteration 700 : Loss 1.3178
Iteration 710 : Loss 1.3144
Iteration 720 : Loss 1.3111
Iteration 730 : Loss 1.3079
Iteration 740 : Loss 1.3047
Iteration 750 : Loss 1.3017
Iteration 760 : Loss 1.2987
Iteration 770 : Loss 1.2957
Iteration 780 : Loss 1.2929
Iteration 790 : Loss 1.2900
Iteration 800 : Loss 1.2873
Iteration 810 : Loss 1.2846
Iteration 820 : Loss 1.2820
Iteration 830 : Loss 1.2794
Iteration 840 : Loss 1.2769
Iteration 850 : Loss 1.2744
Iteration 860 : Loss 1.2720
Iteration 870 : Loss 1.2696
Iteration 880 : Loss 1.2673
Iteration 890 : Loss 1.2650
Iteration 900 : Loss 1.2628
Iteration 910 : Loss 1.2606
Iteration 920 : Loss 1.2584
Iteration 930 : Loss 1.2563
Iteration 940 : Loss 1.2542
Iteration 950 : Loss 1.2522
Iteration 960 : Loss 1.2502
Iteration 970 : Loss 1.2482
Iteration 980 : Loss 1.2463
Iteration 990 : Loss 1.2444
Iteration 1000 : Loss 1.2426
import matplotlib.pyplot as plt
plt.plot(losses)
plt.show()

평가 하기
prediction = model(X_test, W, b)
mse = loss(X_test, W, b, y_test)
mse
0.6750051905605389
plt.scatter(X_test[:, 0], y_test)
plt.scatter(X_test[:, 0], prediction)
plt.show()

3. 라이브러리 활용하기
데이터 준비
tips = sns.load_dataset("tips")
tips = pd.get_dummies(tips, columns=['sex', 'smoker', 'day', 'time'])
tips = tips[['total_bill', 'size', 'sex_Male', 'sex_Female', 'smoker_Yes', 'smoker_No',
'day_Thur', 'day_Fri', 'day_Sat', 'day_Sun', 'time_Lunch', 'time_Dinner', 'tip']]
train, test 데이터 셋 준비
X = tips[['total_bill', 'size', 'sex_Male', 'sex_Female', 'smoker_Yes', 'smoker_No',
'day_Thur', 'day_Fri', 'day_Sat', 'day_Sun', 'time_Lunch', 'time_Dinner']].values
y = tips['tip'].values
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
모델 구현
from sklearn.linear_model import LinearRegression
model = LinearRegression()
모델 학습
model.fit(X_train, y_train)
LinearRegression()
평가 하기
predictions = model.predict(X_test)
predictions
array([2.91436632, 2.00292613, 3.96425583, 3.76380832, 2.14836306,
2.67423448, 3.63934628, 2.29147245, 2.57207155, 2.45851225,
2.90446763, 2.0573337 , 2.11817193, 2.35130838, 1.82976215,
3.10830675, 2.95140176, 3.21602976, 2.56640892, 5.73957295,
3.43490366, 3.22645102, 2.17139823, 1.94180002, 3.16394533,
2.24547894, 2.14497574, 3.21025435, 3.20097595, 6.66803147,
5.01111235, 1.57804024, 3.1909877 , 2.76652194, 2.98412862,
3.85695724, 2.17008741, 5.46673999, 2.35586827, 2.99190732,
2.03271177, 2.48465991, 3.44046814, 2.35532237, 1.92528104,
0.87348926, 1.81911521, 3.04083954, 1.85436902])
from sklearn.metrics import mean_squared_error
mse = mean_squared_error(y_test, predictions)
mse
0.7033566017436103
plt.scatter(X_test[:, 0], y_test, label="true")
plt.scatter(X_test[:, 0], predictions, label="pred")
plt.legend()
plt.show()

'AIFFEL > fundametal' 카테고리의 다른 글
| Fundamental 15 (0) | 2022.01.14 |
|---|---|
| Fundamental 14 (0) | 2022.01.12 |
| Fundamental 13 (0) | 2022.01.10 |
| Fundamental 12 (0) | 2022.01.07 |
| Fundamental 11 (0) | 2022.01.05 |



