Machine Learning - Logistic Regression
import matplotlib.pyplot as plt
months = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
revenue = [52, 74, 79, 95, 115, 110, 129, 126, 147, 146, 156, 184]
plt.plot(months, revenue, "o")
plt.title("Sandra's Lemonade")
plt.xlabel("months")
plt.ylabel("revenue")
plt.show()
[Points and Lines]¶
- line은 아래의 수식처럼 slope(=$m$)와 intercept(=$b$)에 의해 결정됩니다.
- Linear Regression에서의 목표는 우리가 가지고 있는 data에서 "가장 좋은"(="최적의") $m$과 $b$를 찾는 것입니다.
- 위의 데이터에 대해 최적의 $m$과 $b$를 미리 구해 놓았다고 가정하겠습니다. 이때 최적의 $m$과 $b$ 는 각각 10과 53입니다.
m = 10
b = 53
[Practice 1]¶
위에서 주어진 최적의 $m$과 $b$를 이용하여 months
에 대한 예측값 y
를 생성하고 이를 실제 관측값인 revenue
와 그래프를 그려 비교해봅시다.
y = [m*x + b for x in months]
plt.plot(months, revenue, "o")
plt.plot(months, y)
plt.show()
Loss¶
최적의 모델 파라미터($m$과 $b$)를 찾기 위해서는 loss, 혹은 cost을 정의해야합니다. 이때 loss은 모델의 예측값이 실제값과 얼마나 차이가 있는지를 수치로 표현한 것입니다.
아래 그림처럼 해당 실제값에서 예측값까지의 제곱 거리를 loss라고 정의합니다.
- 결론적으로, 이러한 loss를 기준으로 최적의 모델 파라미터인지 아닌지를 판단합니다. 즉, 주어진 전체 데이터에 대해 loss를 최소로 하는 파라미터(m, b)를 찾는 것이 목표입니다. 이를 식으로 표현하면 아래와 같습니다.
[예시]¶
3개의 점 (1, 5), (2, 1), (3, 3)가 주어지고, $y = x$와 $y = 0.5x +1$ 두가지 선이 주어졌습니다.
#주어진 3개의 point
x = [1, 2, 3]
y = [5, 1, 3]
# y = x
m1 = 1
b1 = 0
# y = 0.5x + 1
m2 = 0.5
b2 = 1
주어진 점들에 대해 예측값을 계산해봅니다.
y_pred_1 = [m1*x_val + b1 for x_val in x]
y_pred_2 = [m2*x_val + b2 for x_val in x]
[ Practice 2 ]¶
이 두가지 선 중 위의 식을 토대로 loss를 계산하고, 그 중 loss가 더 작은 선을 골라봅시다.
#result = 0
#for x_val, y_val in zip(x, y):
# value = m1*x_val +b1
# value = y_val-value
# value *= value
total_loss1 = 0
total_loss2 = 0
N = len(x)
for i in range(N):
total_loss1 += (y[i] - y_pred_1[i])**2/N
total_loss2 += (y[i] - y_pred_2[i])**2/N
print("y = x loss", total_loss1)
print("y = 0.5x + 1 loss", total_loss2)
y = x loss 5.666666666666666 y = 0.5x + 1 loss 4.499999999999999
Gradient Descent for Intercept¶
- Gradient Descent은 최적화 알고리즘 중 하나로서 loss function 혹은 cost function의 global 혹은 local minima을 찾을 때 사용됩니다.
- 목표는 데이터의 관계를 잘 표현하는 파라미터 $m$와 $b$을 찾는 것이며, 이것은 gradient descent을 사용하여 loss function을 최소화함을 통해 얻을 수 있습니다.
- 최소의 loss를 찾는 것은 마치 아래의 그림처럼 언덕을 내려가다가 바닥에 도착하면 멈추는 것과 비슷합니다. 즉, 파라미터를 loss가 작아지는 방향으로 조정하다가 최소가되면 멈추게됩니다. 이때 loss가 작아지는 방향은 현재의 경사(=gradient)의 반대 방향을 의미합니다.
<img src=https://miro.medium.com/max/640/1*lYpF8xJ3TiDoq461I0AcOQ.jpeg width=500px>
- 먼저 intercept(=$b$)에 대해서 gradient descent를 실행해봅니다. 앞에서 정의한 loss를 b에 대해 미분하여 gradient를 구할 수 있습니다.
#intercept에 대하여 gradient descent를 수행하는 함수를 구현해봅니다.
def get_gradient_at_b(x, y, b, m):
N = len(x)
diff = 0
for i in range(N):
x_val = x[i]
y_val = y[i]
diff += y_val - ((m * x_val) + b)
b_gradient = -(2/N) * diff
return b_gradient
Gradient Descent for Slope¶
- 마찬가지로 slope(=$m$)에 대한 gradient descent를 실행해봅니다. 이번에는 앞에서 정의한 loss를 $m$에 대해 미분하여 gradient를 구하면 됩니다. 결과는 아래와 같습니다.
#intercept에 대하여 gradient descent를 수행하는 함수를 구현해봅니다.
def get_gradient_at_m(x, y, b, m):
N = len(x)
diff = 0
for i in range(N):
x_val = x[i]
y_val = y[i]
diff +=(x_val) *( y_val - ((m * x_val) + b))
m_gradient = -(2/N) * diff
return m_gradient
Weight Update¶
- $b$와 $m$의 gradient를 이용하여 loss가 감소하는 방향으로 $b$와 $m$을 update합니다. 그리고 loss가 최소가 되면 weight update가 멈추게 되는데, 그때의 $b$와 $m$이 최적의 파라미터가 됩니다.
- 이때 내려가는 보폭을 조절할 수 있는데 이때 사용되는 것이 "learning rate"입니다. 즉, learning rate가 크면 큰 보폭으로 언덕을 내려가고 learning rate가 작으면 작은 보폭으로 언덕을 내려갑니다.
- 즉, "learning rate"를 gradient에 곱해주어 보폭을 사용자가 정할 수 있게합니다.
- 그러나 learning rate는 신중하게 정할 필요가 있습니다.
- learning rate가 너무 작으면 loss의 최솟값에 수렴하는데 시간이 오래 걸립니다.
- learning rate가 너무 크면 최적의 parameter를 얻지 못할 수 있습니다.
learning rate을 사용하여 gradient descent를 수행하여 최적의 파라미터를 찾는 함수를 구현해봅시다.
#step_gradient 함수
def step_gradient(b_current, m_current, x, y, learning_rate):
b_gradient = get_gradient_at_b(x, y, b_current, m_current)
m_gradient = get_gradient_at_m(x, y, b_current, m_current)
b = b_current - (learning_rate * b_gradient)
m = m_current - (learning_rate * m_gradient)
return [b, m]
Example: Sandra’s lemonade stand’s revenue over its first 12 months of being open¶
- 이 함수들을 통해 앞에서 생성했던 data에 대해 한 step 후의 update된 parameter를 구해보겠습니다.
months = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
revenue = [52, 74, 79, 95, 115, 110, 129, 126, 147, 146, 156, 184]
b = 0
m = 0
learning_rate = 0.01
[b, m] = step_gradient(b, m, months, revenue, learning_rate)
print("b : ", b)
print("m : ", m)
b : 2.355 m : 17.78333333333333
최적의 parameter를 찾을 위 과정을 반복해봅니다.
def gradient_descent(x, y, learning_rate, num_iter):
b = 0.
m = 0
for i in range(num_iter):
[b, m] = step_gradient(b, m, x, y, learning_rate)
return [b, m]
위에서 찾은 최적의 파라미터로 linear regression 모델을 만들어 시각화해봅니다.
[optimal_b, optimal_m] = gradient_descent(months, revenue, 0.01, 1000)
print(optimal_b, optimal_m)
49.60215351339813 10.463427732364998
y = [optimal_m * x + optimal_b for x in months]
plt.plot(months, revenue, "o")
plt.plot(months, y)
plt.show()
Scikit-Learn 라이브러리 사용¶
- 지금까지 linear regression algorithm을 직접 구현했습니다. scikit-learn library를 이용하여 보다 간단하게 linear regression을 사용할 수 있습니다. 다큐멘테이션
- scikit-learn에 있는 linear_model 모듈을 통해 linear regression을 실습해보겠습니다.(단, 위에서 언급했던
learning_rate
와num_iterations
은 scikit-learn의 기본값을 사용합니다.) - 아래의 temperature/sales 데이터를 scikit-learn을 이용하여 fitting 해보겠습니다.
import matplotlib.pyplot as plt
import numpy as np
temperature = np.array(range(60, 100, 2))
temperature = temperature.reshape(-1, 1)
sales = [65, 58, 46, 45, 44, 42, 40, 40, 36, 38, 38, 28, 30, 22, 27, 25, 25, 20, 15, 5]
plt.plot(temperature, sales, 'o')
[<matplotlib.lines.Line2D at 0x7f12283b24d0>]
from sklearn.linear_model import LinearRegression
lr = LinearRegression()
lr.fit(temperature, sales)
sales_predict = lr.predict(temperature)
plt.plot(temperature, sales, "o")
plt.plot(temperature, sales_predict,)
plt.show()
계수(Coefficients)¶
fitting된 모델에서 계수(coefficients)를 출력해봅니다.
lr.coef_
array([-1.15225564])
lr.intercept_
125.47819548872182
모델 평가¶
R-Squared (Coefficient of Determination)은 0과 1사이의 값으로 linear regression 모델이 데이터에 얼마나 잘 학습되었는지 나타냅니다. R-Squared가 1에 가까울 수록 모델은 종속 변수(dependent variable)를 잘 예측할 수 있습니다.
#scikit-learn에서 제공하는 score함수 사용하여 r-square값 구해보기
print("R-squared:")
print(lr.score(temperature, sales))
#lr model sales -> temp 에 대해 아래 확률 만큼 설명 가능하다
R-squared: 0.9114088011031334
활동 2: Logistic Regression¶
Logistic Regression은 데이터가 어떠한 특정 카테고리에 속할지를 0과 1사이의 연속적인 확률로 예측하는 회귀 알고리즘 중 하나입니다. 그런 다음, 확률에 기반하여 특정 데이터가 어떤 카테고리에 속할지를 결정하게 되고, 궁극적으로 classification문제를 풀게 됩니다.
[Linear Regression Approach]¶
대학교 강의에서 학생들이 기말 시험을 통과할 수 있을지를 예측해보려고 합니다. 각 학생들이 시험을 통과할 확률을 예측함으로써 통과 여부를 예측할 수 있습니다. 여기서 Linear Regression을 활용하면 어떨까요? 한번 해봅시다.
우선 기말 시험 데이터를 확인 해보겠습니다.
import numpy as np
import matplotlib.pyplot as plt
passed_exam = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1])
passed_exam = passed_exam.reshape(-1, 1)
hours_studied = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
hours_studied = hours_studied.reshape(-1, 1)
#시험에 패스/페일 vs 공부한 시간에 대한 산점도 그려보기
plt.scatter(hours_studied, passed_exam)
plt.show()
각 학생들이 공부한 시간을 num_hours_studied
이라 하고 해당 학생이 중간 시험을 통과한 여부를 y
(y
는 통과한 경우 1, 그렇지 않은 경우 0) 라고 한다면 linear regression을 통해 다음과 같이 직선을 그릴 수 있습니다.
model = LinearRegression()
model.fit(hours_studied, passed_exam)
LinearRegression()
import numpy as np
sample_x = np.linspace(0, 20,100).reshape(-1,1)
probability = model.predict(sample_x).ravel()
plt.plot(hours_studied, passed_exam, "o")
plt.plot(sample_x, probability)
plt.show()
Logistic regression의 예측값은 0과 1사이이므로 위와 같은 linear regression의 한계를 극복할 수 있습니다.
Logistic regression은 다음과 같은 과정으로 수행됩니다.
- 모든 coefficients와 intercept(bias)를 0으로 초기화합니다.
- 각각의 feature를 이에 상응하는 coefficient와 곱한 값과 intercept(bias)를 모두 더해 log-odds를 계산합니다.
- 계산한 log-odds 값을 sigmoid 함수에 전달하여 0 과 1 사이의 확률값을 구합니다.
- 계산한 확률값과 실제 label을 비교하여 loss를 계산하고, gradient descent로 최적의 파라미터를 찾습니다.
- 최적의 파라미터를 찾았다면 classification threshold 값을 조절하여 positive class와 negative class를 어떻게 나눌지를 설정합니다.
[ Log-Odds ]¶
Linear regression에서는 각 feature에 상응하는 weight의 곱과 intercept(bias)를 더해 예측을 하였습니다. Logistic regression에서도 마찬가지지만 log-odds를 계산합니다.
log-odds는 특정 데이터가 positive class에 속할 확률을 표현합니다. 통계에서 특정 사건의 odds(승산)을 계산하는 공식은 다음과 같습니다.
$P(A)$: 특정 사건이 발생할 확률
$1-P(A)$: 특정 사건이 발생하지 않는 확률
$$Odds = \frac{P(A)}{1 - P(A)}$$Odds는 특정 사건이 일어나는 횟수가 특정 사건이 일어나지 않는 횟수보다 얼마나 더 많은지를 의미합니다. 만약 특정 학생이 시험에서 pass할 확률이 0.7이라면, pass하지 못 할 확률은 1 - 0.7 = 0.3 이고, 이 경우 odds를 다음과 같이 계산할 수 있습니다.
$$\text{Odds of passing} = \frac{0.7}{0.3} = 2.33$$Odds는 0과 양의 무한대의 값을 범위로 갖습니다. 그렇기 때문에 제약이 있고, 또, 확률값과 odds 값은 비대칭성을 띕니다.
이러한 한계를 극복하기 위하여 odd에 로그를 취하는것을 log-odds라 하고, 음의 무한대부터 양의 무한대까지의 범위를 갖습니다.
$$\text{Log odds of passing} = log(2.33) = 0.847$$Logistic regression 모델에서 아래와 같이 z 값으로 나타내지는 log-odds 값을 계산할 수 있습니다.
$$log(\frac{P(A)}{1-P(A)})=z=b_0+b_1x_1+b_2x_2+\cdots+b_nx_n$$이로써 특정 데이터의 feature values를 해당 데이터가 positive class에 속할 가능성으로 매핑할 수 있습니다. 이 때 이러한 곱의 합을 dot product(내적) 이라고 합니다. 내적은 numpy의 np.dot() 메서드를 활용하여 쉽게 계산할 수 있습니다.
기말 시험 데이터에서 최적의 coefficient와 intercept가 각각 $0.03$, $-0.3$이라고 가정했을 때의 log-odds를 계산 해봅시다.
calculated_coefficients = 0.03
intercept = -0.3
# log_odds 함수를 정의해봅니다.
def log_odds(features, coefficient, intercept):
return np.dot(features, coefficient) + intercept
# hours_studied 데이터에 대해서 log-odds를 계산해봅니다.
calculated_log_odds = log_odds(hours_studied, calculated_coefficients, intercept)
calculated_log_odds
array([[-0.3 ], [-0.27], [-0.24], [-0.21], [-0.18], [-0.15], [-0.12], [-0.09], [-0.06], [-0.03], [ 0. ], [ 0.03], [ 0.06], [ 0.09], [ 0.12], [ 0.15], [ 0.18], [ 0.21], [ 0.24], [ 0.27]])
[ Sigmoid Function ]¶
Sigmoid Function은 log-odds인 $z$ 값을 취해서 아래와 같이 0 과 1 사이의 값을 반환합니다.
$$h_θ = σ(z) = \frac{1}{1+e^{-z}}$$<img src=https://upload.wikimedia.org/wikipedia/commons/thumb/8/88/Logistic-curve.svg/1200px-Logistic-curve.svg.png width=500px>
Logistic Regression이 특정 데이터가 positive class에 속할 확률을 계산합니다.
# sigmoid 함수 정의하기
def sigmoid(z):
return 1/(1+np.exp(-z))
# 확률 계산해보기
probabilities = sigmoid(calculated_log_odds)
probabilities
array([[0.42555748], [0.4329071 ], [0.44028635], [0.44769209], [0.45512111], [0.46257015], [0.47003595], [0.47751518], [0.4850045 ], [0.49250056], [0.5 ], [0.50749944], [0.5149955 ], [0.52248482], [0.52996405], [0.53742985], [0.54487889], [0.55230791], [0.55971365], [0.5670929 ]])
[ Log-Loss ]¶
이제 최적의 coefficients와 intercept를 구해보겠습니다. 이를 구하기 위해서는 주어진 모델의 예측이 실제 데이터에 얼마나 가까운지 측정하는 기준이 필요합니다. 이를 loss function 혹은 cost function이라고 합니다.
모델이 데이터에 ‘fit’ 하단걸 측정하기 위해선 먼저 각 데이터에 대한 loss를 계산한뒤 loss의 평균을 내야합니다. Logistic regression에서의 loss function은 Log Loss라고 불리며, 공식은 다음과 같습니다.
- m 은 전체 데이터의 개수입니다.
- $y^{(i)}$는 $i$ 번째 데이터의 class 입니다.
- $a^{(i)}$는 $i$ 번째 데이터의 log-odds 값에 sigmoid 를 취한 값입니다. 즉 $i$ 번째 데이터가 positive class에 속할 확률을 나타냅니다.
만약 $i$ 번째 데이터의 class가 $y=1$ 이라면 해당 데이터에 대한 loss는 다음과 같습니다.
$$loss_{i(y=1)} = -log(a^{(i)})$$loss를 최소화 시키려면 $a^{(i)}$ 값이 커야 합니다. 즉, 예측된 확률 값이 원래 class인 1 에 가까울수록 loss는 줄어들게 됩니다.
반대로 $i$ 번째 데이터의 class가 $y=0$ 인 경우는 다음과 같습니다..
$$loss_{i(y=0)} = -log(1-a^{(i)})$$loss를 최소화 시키려면 $a^{(i)}$값이 작아야 합니다. 즉, 예측된 확률 값이 원래 class이 0에 가까울수록 loss는 줄어들게 됩니다.
아래의 그래프는 class가 $y=1$, $y=0$ 일 때 $a$값에 따라 loss가 어떻게 변화하는지를 나타냅니다.
그래프를 보면 올바르게 예측할수록 loss가 줄어드는 것을 볼 수 있습니다. 반대로 잘 못 예측하게 되면 loss가 크게 증가하는데, 이는 모델이 잘못 예측할 때 패널티를 강하게 줌으로써 올바른 예측을 할 수 있도록 유도할 수 있습니다.
# log_loss 함수 구현해보기
def log_loss(probabilities, actual_class):
return np.sum(-(1 / actual_class.shape[0]) * (actual_class * np.log(probabilities)
+ (1 - actual_class) * np.log(1 - probabilities)))
log_loss(probabilities, passed_exam)
0.6279073897953891
[ Classification Thresholding ]¶
Logistic Regression은 예측된 확률 값이 임계값을 넘느냐 못 넘느냐에 따라서 class를 분류합니다. 이 임계값을 classification threshold 라고 합니다.
Classification threshold의 기본값은 0.5 입니다. 만약 특정 데이터의 예측된 확률 값이 0.5 보다 크거나 같다면 해당 데이터는 positive class로 분류됩니다. 반대로 예측된 확률 값이 0.5 보다 낮다면 negative class로 분류됩니다.
만약 더욱 엄격하게하고자 한다면 threshold를 0.6이나 0.7로 조정할 수 있습니다. 즉, 모델이 positive class를 더 적게 예측할 수 있도록 하는 것입니다.
이에 대해 예측된 확률값이 임계값을 넘으면 1, 그렇지 않으면 0 을 반환하는 함수를 구현해보겠습니다.
# predict_class함수 구현하기
def predict_class(features, coefficients, intercept, threshold):
odd = log_odds(features, coefficients, intercept)
predicted_probability = sigmoid(odd)
result = []
for i in predicted_probability:
if i >= threshold:
result.append([1])
else:
result.append([0])
return result
# threshold=0.5로 최종 예측 해보기
predict_class(hours_studied, calculated_coefficients, intercept, 0.5)
[[0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1]]
이번에는 더욱 엄격하게 threshold를 0.55로 설정하여 위의 결과와 비교해봅니다.
#threshold=0.55로 최종 예측 해보기
predict_class(hours_studied, calculated_coefficients, intercept, 0.55)
[[0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [1], [1], [1]]
[ Scikit-Learn ]¶
scikit-learn에서 제공하는 메서드를 활용하여 Logistic Regression을 구현해봅니다.
from sklearn.linear_model import LogisticRegression
model = LogisticRegression()
model.fit(hours_studied, passed_exam)
/usr/local/lib/python3.7/dist-packages/sklearn/utils/validation.py:993: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel(). y = column_or_1d(y, warn=True)
LogisticRegression()
probability = model.predict_proba(sample_x)[:, 1]
plt.plot(hours_studied, passed_exam, 'o')
plt.plot(sample_x, probability)
plt.xlabel('hours studied')
plt.show()
predicted_class
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
과제¶
- 이전 실습2 과제의 코드를 이용하여 titanic.csv 데이터의 url를 통해
pandas
DataFrame
으로 데이터를 가져옵니다. 이전 실습2 과제처럼 동일하게
1) 전체 데이터에서
Survived
,Pclass
,Sex
,Age
,SibSp
,Parch
,Fare
,Embarked
feature을 고르고,2)
Age
feature의 NA값을 drop하고,3)
Sex
feature을scikit-learn
의LabelEncoder
을 사용하여 정수형으로 변환합니다..head()
를 사용하여 데이터의 첫 다섯개 instance를 출력합니다.- 주어진
onehot()
함수를 읽어보고, 어떤 순서와 방식으로 데이터를 변환하는지 서술합니다. 필요하다면 각 메소드의 디큐멘테이션을 참고합니다. onehot()
함수를 사용하여Embarked
feature을 one-hot encoding 합니다.<img src=https://i.imgur.com/mtimFxh.png width=400px>
.head()
를 사용하여 one-hot encoding이 올바르게 되었는지 확인합니다.아래 주어진 코드를 이용하여 데이터를 feature 변수
x
와 label 변수y
로 분리하고train_test_split()
함수를 이용하여 데이터를 train data과 test data으로 나눕니다. 만약 deterministic한 결과를 원한다면random_state
파라미터를 지정해줍니다. (지정하지 않아도 과제 점수에는 상관이 없습니다.)# 데이터를 feature X와 label y로 나눕니다. y = df[['Survived']].to_numpy().ravel() x = df.drop(columns=['Survived'])
LogisticRegression()
모델을 생성합니다. 이때, 모델 파라미터는max_iter
을1000
으로 지정해줍니다. 이 모델을 train data에 fit 해봅니다.- test data에 대하여 score을 계산합니다.
- 훈련된 Logistic regression 모델의
.coef_
를 출력해보고,.coef_
의 절대값이 큰 feature 2개와 절대값이 작은 feature 2개가 무엇인지, 그리고 각각에 대해 그 값이 몇인지 서술합니다. //의미 서술 X
import pandas as pd
def onehot(data, feature):
'''
data의 feature column을 one hot으로 변환해줍니다.
data: pandas DataFrame
feature: string, 데이터 프레임의 column 이름
'''
return pd.concat([data, pd.get_dummies(data[feature], prefix=feature)], axis=1).drop([feature], axis=1)
data_url = "https://raw.githubusercontent.com/inikoreaackr/ml_datasets/main/titanic.csv"
data = pd.read_csv(data_url)
data.columns
data = data [['Survived', 'Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked']]
data = data.dropna()
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
data.Sex = le.fit_transform(data.Sex)
data.head()
Survived | Pclass | Sex | Age | SibSp | Parch | Fare | Embarked | |
---|---|---|---|---|---|---|---|---|
0 | 0 | 3 | 1 | 22.0 | 1 | 0 | 7.2500 | S |
1 | 1 | 1 | 0 | 38.0 | 1 | 0 | 71.2833 | C |
2 | 1 | 3 | 0 | 26.0 | 0 | 0 | 7.9250 | S |
3 | 1 | 1 | 0 | 35.0 | 1 | 0 | 53.1000 | S |
4 | 0 | 3 | 1 | 35.0 | 0 | 0 | 8.0500 | S |
onehot?
data = onehot(data, 'Embarked')
주어진
onehot()
함수를 읽어보고, 어떤 순서와 방식으로 데이터를 변환하는지 서술합니다. 필요하다면 각 메소드의 디큐멘테이션을 참고합니다.<img src=https://i.imgur.com/mtimFxh.png width=400px>
data의 feature column을 0과 1의 값을 가지는 데이터로 구별해주는 인코딩이다. 표현하고자 하는 인덱스에는 데이터 1을, 다른 인덱스는 0으로 표현된다.
- 먼저 데이터에 대한 정수 인코딩이 진행된다. 각각의 요소는 다른 정수값을 가지는 데이터로 표현된다. EX 1 : RED 2 : YELLOW 3 : GREEN
- 값의 개수만큼의 행렬 구조가 만들어지고 표현하고자 하는 데이터의 고유한 값을 index로 보아 해당하는 위치에는 1을 다른 값을 지니는 요소의 위치에 0을 부여한다.
y = data[['Survived']].to_numpy().ravel()
x = data.drop(columns=['Survived'])
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(x,y,test_size = .3)
model_titanic = LogisticRegression(max_iter=1000)
model_titanic.fit(x_train, y_train)
LogisticRegression(max_iter=1000)
print(model_titanic.score(x_test,y_test))
0.7990654205607477
coef = model_titanic.coef_
print(coef, "\n")
for i in range(len(x.columns)):
print(x.columns[i],":",coef[0][i])
[[-1.13588865e+00 -2.58221815e+00 -4.56647796e-02 -3.35399948e-01 -4.22408897e-02 2.20349750e-03 4.47231111e-01 -5.75288314e-01 1.18618995e-01]] Pclass : -1.1358886533804295 Sex : -2.5822181505918125 Age : -0.045664779628737426 SibSp : -0.33539994797221 Parch : -0.04224088972835762 Fare : 0.0022034975000360204 Embarked_C : 0.4472311112889102 Embarked_Q : -0.5752883138433935 Embarked_S : 0.11861899501285339
절대값이 큰 feature
- Sex : 2.40791938831739
- Pclass : 1.174206879583307
절대값이 작은 feature
- Fare : 0.00041304172578507105
- Age : 0.05062299635153086
과제 2¶
실습에서는 logistic regression 함수의 cost fuction까지 구현을 해보았습니다. 두번째 과제는 logistic regression cost function의 gradient descent을 함수로 구현하여 최적의 파라미터까지 찾아 최종 모델을 훈련시키는 logistic regression 모델을 scratch부터 구현하는 것 입니다. 데이터는 logistic regression 실습에서 사용한 hours_studied
, passed_exam
데이터를 사용합니다.
세부 사항:
coefficient의 gradient을 계산하는 함수를 작성합니다. ($\frac{\delta cost}{\delta w}$)
intercept의 gradient을 계산하는 함수를 작성합니다. ($\frac{\delta cost}{\delta b}$)
두 gradient을 받아 step gradient을 실행하는 함수를 작성합니다.
위 과정을 반복하여 최적의 파라미터를 찾는 logistic regression 함수를 작성합니다.
데이터에 최종 모델을 학습시키고, classification을 잘 수행하는지 결과를 시각화해 확인해봅니다.
안내 사항:
learning rate, number of iteration은 임의로 적당한 값을 본인이 설정해봅니다.
과제 2번은 타 수강생 한 명과 협업이 가능합니다. 협업한 수강생의 이름 및 학번을 개제해주시기 바랍니다.
참고한 자료의 출처를 필히 기재해주시기 바랍니다.
# coefficient gradient : SUM(x(a(i) - y))/m
def get_coef_gradient(x, y, y_predict):
[[grad]] = (1/len(x)) * np.dot(x.T, y_predict - y)
return grad
get_coef_gradient(hours_studied, passed_exam, probabilities)
-1.5871075590969737
# intercept gradient : SUM(a(i) - y)/m
def get_intercept_gradient(y, y_predict):
return (1/len(y)) * np.sum(y_predict - y)
get_intercept_gradient(passed_exam, probabilities)
0.046277874159417066
def log_loss_step_gradient(weight_current, intercept_current, x, y, y_predicted, learning_rate):
coef = get_coef_gradient (x, y, y_predicted)
intercept = get_intercept_gradient(y, y_predicted)
weight = weight_current - (learning_rate * coef)
intercept = intercept_current - (learning_rate * intercept)
return [weight, intercept]
def log_loss_gradient_descent(x, y, learning_rate, num_iter):
opt_weight = 0
opt_intercept = 0
odd = log_odds(x, weight, intercept)
y_predict = sigmoid(odd)
print(y_predict)
trace = []
trace.append(log_loss(y_predict, y))
for j in range(num_iter):
[opt_weight, opt_intercept] = log_loss_step_gradient(opt_weight, opt_intercept, x, y, y_predict, learning_rate)
odd = log_odds(x, opt_weight, opt_intercept)
y_predict = sigmoid(odd)
trace.append(log_loss(y_predict, y))
return [opt_weight, opt_intercept], trace
[weight, intercept], trace = log_loss_gradient_descent(hours_studied, passed_exam, 0.05, 1000)
print("weight : ", weight, "\n")
print("intercept : ", intercept, "\n")
[[0.42555748] [0.51673783] [0.60681714] [0.69017318] [0.76276619] [0.82271945] [0.87010168] [0.90626282] [0.93313104] [0.95269988] [0.96674609] [0.97672306] [0.98375699] [0.98868999] [0.99213681] [0.99453899] [0.99621011] [0.99737121] [0.99817723] [0.99873643]] weight : 0.36710895563627843 intercept : -3.6293894250817496
def norm_x(x):
return x-x.mean()
y_prediction = sigmoid(log_odds(hours_studied, weight, intercept))
plt.plot(hours_studied, passed_exam, "o")
plt.plot(hours_studied, y_prediction)
[<matplotlib.lines.Line2D at 0x7f122808e390>]
# model의 log_loss cost변화
plt.title('Log-loss over iterations')
plt.plot(trace)
plt.xlabel('iteration')
plt.ylabel('Log-loss')
plt.show()
Comments