TP (True Positive) : 실제 Positive를 Positive라고 맞힌 경우
FN (False Negative) : 실제 Positive를 Negative라고 틀리게 예측한 경우
TN (True Negative) : 실제 Negative를 Negative라고 맞힌 경우
FP (False Positive) : 실제 Negative를 Positive라고 틀리게 예측한 경우
-> Positive(1), Negative(0)
<모델 평가 지표>
1) Accuracy : 전체 데이터 중 맞게 예측한 것의 비율
2) Precision : 양성(1)이라고 예측한 것 중에서 실제 양성(1)의 비율
-> TP / (TP + FP)
3) Recall : 참(1)인 데이터들 중에서 참(1)이라고 예측한 것(재현율)
-> TP / (TP + FN)
4) Fall-Out : 실제 양성이 아닌데, 양성이라고 잘못 예측한 경우
(실제 0인것들 중에서 1이라고 예측한 것)
-> FP / (FP + TN)
Recall은 암환자(1)를 암이 아니라고(0) 진단할 가능성을 놓치지 않기 위한 상황에서 필요함
Precision은 중요한 메일을 스팸메일이라고 오해할 가능성을 놓치지 않기 위한 상황에서 필요함
분류 모델은 그 결과를 속할 비율(확률)을 반환함
-> 지금까지는 그 비율에서 threshold를 0.5라고 하고, 그것보다 크면 1, 작으면 0으로 결과를 반영함
threshold를 변경해 가면서 모델 평가 지표들 관찰해보기
<정리>
1) Recall은 실제 참인 데이터 중에서 참이라고 예측한 데이터의 비율
2) Precision은 참이라고 예측한 것 중에서 실제 참인 데이터의 비율
3) 실제 양성인 데이터를 음성이라고 판단하면 안 되는 경우라면 Recall이 중요하고, 이 경우는 Threshold를 0.3 혹은 0.4로 선정해야 함 (ex-암환자 선별)
4) 실제 음성인 데이터를 양성이라고 판단하면 안 되는 경우라면 Precision이 중요하고, 이 경우는 Threshold를 0.8 혹은 0.9로 선정해야 함 (ex-스팸메일)
-> 그러나 Recall과 Precision은 서로 영향을 주기 때문에 한 쪽을 극단적으로 높게 설정해서는 안 됨
1) ROC 곡선
2) AUC
3) ROC 커브 그려보기
import pandas as pd
red_url = 'https://raw.githubusercontent.com/PinkWink/ML_tutorial' + \
'/master/dataset/winequality-red.csv'
white_url = 'https://raw.githubusercontent.com/PinkWink/ML_tutorial' + \
'/master/dataset/winequality-white.csv'
red_wine = pd.read_csv(red_url, sep=';')
white_wine = pd.read_csv(white_url, sep=';')
red_wine['color'] = 1.
white_wine['color'] = 0.
wine = pd.concat([red_wine, white_wine])
wine['taste'] = [1. if grade>5 else 0. for grade in wine['quality']]
X = wine.drop(['taste', 'quality'], axis=1)
y = wine['taste']
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=13)
wine_tree = DecisionTreeClassifier(max_depth=2, random_state=13)
wine_tree.fit(X_train, y_train)
y_pred_tr = wine_tree.predict(X_train)
y_pred_test = wine_tree.predict(X_test)
print('Train Acc : ', accuracy_score(y_train, y_pred_tr))
print('Test Acc : ', accuracy_score(y_test, y_pred_test))
from sklearn.metrics import accuracy_score, precision_score
from sklearn.metrics import recall_score, f1_score
from sklearn.metrics import roc_auc_score, roc_curve
print('Accuracy : ', accuracy_score(y_test, y_pred_test))
print('Recall : ', recall_score(y_test, y_pred_test))
print('Precision : ', precision_score(y_test, y_pred_test))
print('AUC Score : ', roc_auc_score(y_test, y_pred_test))
print('F1 Score : ', f1_score(y_test, y_pred_test))
import matplotlib.pyplot as plt
%matplotlib inline
pred_proba = wine_tree.predict_proba(X_test)[:, 1] # 모든 행의 첫 번째만 (1일 확률만)
fpr, tpr, thresholds = roc_curve(y_test, pred_proba)
plt.figure(figsize=(10,8))
plt.plot([0,1], [0,1]) # (0,0), (1,1)을 잇는 직선그래프 그림 (보조선 역할)
plt.plot(fpr, tpr)
plt.grid()
plt.show()
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-3, 2, 100) # -3부터 2까지 숫자 중 균등한 간격의 100개를 가져옴
y = 3 * x**2 + 2
plt.figure(figsize=(12,8))
plt.plot(x, y)
plt.grid()
plt.xlabel('$x$') # $$ 사이에 쓰면 italic으로 기울어지는등 수학식으로 나옴
plt.ylabel('$3x^2 +2$')
x = np.linspace(-5, 5, 100)
y1 = 3*x**2 + 2
y2 = 3*(x+1)**2 + 2
plt.figure(figsize=(12,8))
plt.plot(x, y1, lw=2, ls='dashed', label='$y=3x^2 +2$')
plt.plot(x, y2, label='$y=3(x+1)^2 +2$')
plt.legend(fontsize=15)
plt.xlabel('$x$', fontsize=25)
plt.ylabel('$y$', fontsize=25)
plt.show()
-> x 자리에 x+1이 들어가면, x축 방향으로 -1 움직임 (평행이동)
x = np.linspace(-2, 2, 100)
a11, a12, a13 = 2, 3, 4
y11, y12, y13 = a11**x, a12**x, a13**x
a21, a22, a23 = 1/2, 1/3, 1/4
y21, y22, y23 = a21**x, a22**x, a23**x
fig, ax = plt.subplots(1, 2, figsize=(12, 6))
ax[0].plot(x, y11, color='k', label='$2^x$')
ax[0].plot(x, y12, '--', color='k', label='$3^x$')
ax[0].plot(x, y13, ':', color='k', label='$4^x$')
ax[0].legend(fontsize=20)
ax[1].plot(x, y21, color='k', label='$(1/2)^x$')
ax[1].plot(x, y22, '--', color='k', label='$(1/3)^x$')
ax[1].plot(x, y23, ':', color='k', label='$(1/4)^x$')
ax[1].legend(fontsize=20)
plt.show()
-> x 자리에 -x가 들어가면 좌우 대칭의 형태가 됨
x = np.linspace(0, 10)
plt.figure(figsize=(6,6))
plt.plot(x, x**2, '--', color='k', label='$x^2$')
plt.plot(x, 2**x, color='k', label='$2^x$')
def log(x, base) :
return np.log(x)/np.log(base)
x1 = np.linspace(0.0001, 5, 1000)
x2 = np.linspace(0.01, 5, 100)
y11, y12 = log(x1, 10), log(x2, np.e)
y21, y22 = log(x1, 1/10), log(x2, 1/np.e)
fig, ax = plt.subplots(1, 2, figsize=(12, 6))
ax[0].plot(x1, y11, label=r"$\log_{10} x$", color='k')
ax[0].plot(x2, y12, '--', label="$\log_{e} x$", color='k')
ax[0].set_xlabel('$x$', fontsize=25)
ax[0].set_ylabel('$y$', fontsize=25)
ax[0].legend(fontsize=20, loc='lower right')
ax[1].plot(x1, y21, label=r"$\log_{1/10} x$", color='k')
ax[1].plot(x2, y22, '--', label="$\log_{1/e} x$", color='k')
ax[1].set_xlabel('$x$', fontsize=25)
ax[1].set_ylabel('$y$', fontsize=25)
ax[1].legend(fontsize=20, loc='upper right')
plt.show()
z = np.linspace(-10, 10, 100)
sigma = 1/(1+np.exp(-z))
plt.figure(figsize=(12,8))
plt.plot(z, sigma)
plt.xlabel('$z$', fontsize=25)
plt.ylabel('$\sigma(z)$', fontsize=25)
plt.show()
-> 무조건 0과 1사이의 값을 가짐
u = np.linspace(0, 1, 30)
v = np.linspace(0, 1, 30)
U, V = np.meshgrid(u, v)
X = U
Y = V
Z = (1+U**2) + (V/(1+V**2))
fig = plt.figure(figsize=(7, 7))
ax = plt.axes(projection='3d')
ax.xaxis.set_tick_params(labelsize=15)
ax.yaxis.set_tick_params(labelsize=15)
ax.zaxis.set_tick_params(labelsize=15)
ax.set_xlabel(r'$x$', fontsize=20)
ax.set_ylabel(r'$y$', fontsize=20)
ax.set_zlabel(r'$z$', fontsize=20)
ax.scatter3D(X, Y, Z, marker='.', color='gray')
plt.show()
x = np.linspace(-4, 4, 100)
y = x**3 - 15*x + 30 # f(x)
z = np.log(y) # g(y)
fig, ax = plt.subplots(1, 2, figsize=(12, 6))
ax[0].plot(x, y, label=r'$x^3 - 15x + 30$', color='k')
ax[0].legend(fontsize=18)
ax[1].plot(y, z, label=r'$\log(y)$', color='k')
ax[1].legend(fontsize=18)
plt.show()
fig, ax = plt.subplots(1, 2, figsize=(12, 6))
ax[0].plot(x, z, '--', label=r'$\log(f(x))$', color='k')
ax[0].legend(fontsize=18)
ax[1].plot(x, y, label=r'$x^3 - 15x + 30$', color='k')
ax[1].legend(fontsize=18)
ax_tmp = ax[1].twinx()
ax_tmp.plot(x, z, '--', label=r'$\log(f(x))$', color='k')
plt.show()
samples = [1, 7, 9, 16, 36, 39, 45, 45, 46, 48, 51, 100, 101]
tmp_y = [1] * len(samples)
plt.figure(figsize=(12, 4))
plt.scatter(samples, tmp_y)
plt.grid()
plt.show()
np.median(samples)
np.percentile(samples, 25) # 25퍼센트 지점
np.percentile(samples, 75)
iqr = np.percentile(samples, 75) - np.percentile(samples, 25)
iqr * 1.5
q1 = np.percentile(samples, 25)
q2 = np.median(samples)
q3 = np.percentile(samples, 75)
iqr = q3 - q1
upper_fence = q3 + iqr*1.5
lower_fence = q1 - iqr*1.5
plt.figure(figsize=(12, 4))
plt.scatter(samples, tmp_y)
plt.axvline(x=q1, color='black')
plt.axvline(x=q2, color='red')
plt.axvline(x=q3, color='black')
plt.axvline(x=upper_fence, color='black', ls='dashed')
plt.axvline(x=lower_fence, color='black', ls='dashed')
plt.grid()
plt.show()
import seaborn as sns
plt.figure(figsize=(12, 4))
sns.boxplot(samples)
plt.grid()
plt.show()
<제로베이스 데이터 취업 스쿨>