- 로지스틱 회귀분석
: 이항분류 분석
: logit(), glm()
: 독립변수 : 연속형, 종속변수 : 범주형
- 출력된 연속형 자료에 대해 odds -> odds ratio -> logit function -> sigmoid function으로 이항분류
- odds(오즈)
: 확률을 바꾼 값. 성공확률(혹은 1일)이 실패확률(0일)에 비해 몇 배 더 높은가를 나타낸다.
- odds ratio(오즈비)
: 두 개의 오즈 비율. 확률 p의 범위가 (0,1)이라면 Odds(p)의 범위는 (0, ∞)이 된다.
- logit(로짓)
: 오즈비에 로그를 취한 값. Odds ratio에 로그함수를 취한 log(Odds(p))은 입력값의 범위가 (-∞ ~ ∞)이 된다. 즉, 범위가 실수 전체다. 이러한 입력 값의 범위를 (0 ~ 1)로 조정한다.
- sigmoid(시그모이드)
: log(Odds(p))의 범위가 실수이므로 이 값에 대한 선형회귀분석을 하는 것은 의미가 있다. 왜냐하면 오즈비(두 개의 odd 비율)에 로그를 씌우면 오즈비 값들이 정규분포를 이루기 때문이다. log(Odds(p))=wx+b로 선형회귀분석을 실시해서 w와 b를 얻을 수 있다. 위 식을 이용한 것이 sigmoid function이다. 이를 통해 0.5을 기준으로 1과 0의 양분된 값을 된다.
* logistic1.py
import math
import numpy as np
from sklearn.metrics._scorer import accuracy_scorer
def sigFunc(x):
return 1 / ( 1 + math.exp(-x)) # math.exp(x) : e^x
print(sigFunc(0.6))
print(sigFunc(0.2))
print(sigFunc(6))
print(sigFunc(-6))
print(np.around(sigFunc(6))) # 1.0
print(np.around(sigFunc(-6))) # 0.0
import statsmodels.api as sm
mtcars = sm.datasets.get_rdataset('mtcars').data
print(mtcars.head(3)) # mtcars data read
'''
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
'''
print(mtcars['am'].unique()) # [1 0]
import statsmodels.api as sm
sm.datasets.get_rdataset('데이터명').data : 내장 데이터 셋의 데이터 read.
- 방법1 : logit()
import statsmodels.formula.api as smf
formula = 'am ~ mpg + hp' # 연비, 마력 -> 자/수동 상관관계
result = smf.logit(formula=formula, data=mtcars).fit()
print(result)
'''
Optimization terminated successfully.
Current function value: 0.300509
Iterations 9
<statsmodels.discrete.discrete_model.BinaryResultsWrapper object at 0x000001F6244B8040>
'''
print(result.summary())
# p-value < 0.05 => 유효
pred = result.predict(mtcars[:10])
#print('예측값 : \n', pred)
print('예측값 : \n', np.around(pred))
'''
예측값 :
Mazda RX4 0.0
Mazda RX4 Wag 0.0
Datsun 710 1.0
Hornet 4 Drive 0.0
Hornet Sportabout 0.0
Valiant 0.0
Duster 360 0.0
Merc 240D 1.0
Merc 230 1.0
Merc 280 0.0
'''
print('실제값 : \n', mtcars['am'][:10])
'''
실제값 :
Mazda RX4 1
Mazda RX4 Wag 1
Datsun 710 1
Hornet 4 Drive 0
Hornet Sportabout 0
Valiant 0
Duster 360 0
Merc 240D 0
Merc 230 0
Merc 280 0
'''
import statsmodels.formula.api as smf
smf.logit(formula='종속변수 ~ 독립변수 + ...', data=데이터).fit() : 로지스틱 회귀 모델 생성
model.predict(데이터) : 모델에 대한 예측 값 산출
- 분류정확도
conf_tab = result.pred_table() # confusion matrix
print(conf_tab)
'''
예측값 p n
실제값 참 [[16.(TP) 3.(FN)]
거짓 [ 3.(FP) 10.(TN)]]
'''
print('분류 정확도 :', (16+10) / len(mtcars)) # 0.8125
print('분류 정확도 :', (conf_tab[0][0] + conf_tab[1][1])/ len(mtcars)) # 0.8125
from sklearn.metrics import accuracy_score
pred2 = result.predict(mtcars)
print('분류 정확도 :', accuracy_score(mtcars['am'], np.around(pred2))) # 0.8125
model.pred_table() : confusion matrix 생성
from sklearn.metrics import accuracy_score
accuracy_score(실제 값, 예측 값) : 분류 정확도 산출
예측값 | |||
positive | negative | ||
실제값 | 참 | TP | FN |
거짓 | FP | TN |
=> TP, TN : 예측값과 실제값이 일치
=> 정확도(accuracy) = TP + TN / 전체 개수
=> 정밀도(pecision) = TP / (TP + FP)
=> 재현율(recall) = TP / (TP + FN)
=> 특이도 = TN / (FP + TN)
=> F1 score = 2 x 재현율 x 정밀도 / (재현율 + 정밀도)
- 방법2 : glm()
import statsmodels.formula.api as smf
import statsmodels.api as sm
result2 = smf.glm(formula=formula, data=mtcars, family=sm.families.Binomial()).fit()
print(result2)
print(result2.summary())
glm_pred = result2.predict(mtcars[:5])
print('glm 예측값 :\n', glm_pred)
'''
Mazda RX4 0.250047
Mazda RX4 Wag 0.250047
Datsun 710 0.558034
Hornet 4 Drive 0.355600
Hornet Sportabout 0.397097
'''
print('실제값 :\n', mtcars['am'][:5])
glm_pred2 = result2.predict(mtcars)
print('분류 정확도 :', accuracy_score(mtcars['am'], np.around(glm_pred2))) # 0.8125
smf.glm(formula='종속변수 ~ 독립변수 +...', data=데이터, family=sm.families.Binomial()).fit() : 로지스틱 회귀 모델 생성
- 새로운 값을 분류
new_df = mtcars.iloc[:2].copy()
new_df['mpg'] = [10, 30]
new_df['hp'] = [100, 130]
print(new_df)
'''
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 10 6 160.0 100 3.9 2.620 16.46 0 1 4 4
Mazda RX4 Wag 30 6 160.0 130 3.9 2.875 17.02 0 1 4 4
'''
glm_pred_new = result2.predict(new_df)
print('새로운 값 분류 결과 :\n', np.around(glm_pred_new))
print('새로운 값 분류 결과 :\n', np.rint(glm_pred_new))
'''
Mazda RX4 0.0
Mazda RX4 Wag 1.0
'''
import pandas as pd
new_df2 = pd.DataFrame({'mpg':[10, 35], 'hp':[100, 145]})
glm_pred_new2 = result2.predict(new_df2)
print('새로운 값 분류 결과 :\n', np.around(glm_pred_new2))
'''
0 0.0
1 1.0
'''
np.around(숫자) : 반올림
np.rint(숫자) : 반올림
- 로지스틱 회귀분석
: 날씨 예보 - 강수 예보
* logistic2.py
import pandas as pd
from sklearn.model_selection._split import train_test_split
import statsmodels.api as sm
import statsmodels.formula.api as smf
import numpy as np
data = pd.read_csv('../testdata/weather.csv')
print(data.head(2), data.shape, data.columns) # (366, 12)
'''
Date MinTemp MaxTemp Rainfall ... Cloud Temp RainToday RainTomorrow
0 2016-11-01 8.0 24.3 0.0 ... 7 23.6 No Yes
1 2016-11-02 14.0 26.9 3.6 ... 3 25.7 Yes Yes
Index(['Date', 'MinTemp', 'MaxTemp', 'Rainfall', 'Sunshine', 'WindSpeed',
'Humidity', 'Pressure', 'Cloud', 'Temp', 'RainToday', 'RainTomorrow']
'''
data2 = pd.DataFrame()
data2 = data.drop(['Date', 'RainToday'], axis=1)
data2['RainTomorrow'] = data2['RainTomorrow'].map({'Yes':1, 'No':0})
print(data2.head(5))
'''
MinTemp MaxTemp Rainfall Sunshine ... Pressure Cloud Temp RainTomorrow
0 8.0 24.3 0.0 6.3 ... 1015.0 7 23.6 1
1 14.0 26.9 3.6 9.7 ... 1008.4 3 25.7 1
2 13.7 23.4 3.6 3.3 ... 1007.2 7 20.2 1
3 13.3 15.5 39.8 9.1 ... 1007.0 7 14.1 1
4 7.6 16.1 2.8 10.6 ... 1018.5 7 15.4 0
'''
데이터.drop([칼럼1, ... ], axis=1) : 칼럼 단위 자르기
데이터.map({'key1':value1, 'key2':value2}) : 데이터의 key와 동일할 경우 value로 set.
- train (모델을 학습) / test (모델을 검증)로 분리 : 과적합 분리
train, test = train_test_split(data2, test_size=0.3, random_state = 42) # 샘플링, random_state : seed no
print(train.shape, test.shape) # (256, 10) (110, 10)
from sklearn.model_selection._split import train_test_split
train_test_split(데이터, test_size=0.3, random_state = seed넘버) : 데이터를 train, test로 test_size 비율로 분할.
- 분류 모델
#my_formula = 'RainTomorrow ~ MinTemp + MaxTemp + ...'
col_sel = "+".join(train.columns.difference(['RainTomorrow'])) # difference(x) : x 제외
my_formula = 'RainTomorrow ~ ' + col_sel
print(my_formula)
# RainTomorrow ~ Cloud+Humidity+MaxTemp+MinTemp+Pressure+Rainfall+Sunshine+Temp+WindSpeed
model = smf.logit(formula=my_formula, data = train).fit()
#model = smf.glm(formula=my_formula, data = train, family=sm.families.Binomial()).fit()
print(model)
print(model.params)
print('예측값:\n', np.around(model.predict(test)[:5]))
'''
193 0.0
33 0.0
15 0.0
310 0.0
57 0.0
'''
print('실제값:\n', test['RainTomorrow'][:5])
'''
193 0
33 0
15 0
310 0
57 0
'''
구분자.join(데이터.difference([x, .. ])) : 데이터 사이에 구분자를 포함하여 결합. difference(x) : join시 x는 제외.
- 정확도
con_mat = model.pred_table() # smf.logit()에서 지원, smf.glm()에서 지원하지않음.
print('con_mat : \n', con_mat)
'''
[[197. 9.]
[ 21. 26.]]
'''
print('train 분류 정확도 :', (con_mat[0][0] + con_mat[1][1])/ len(train)) # 0.87109375
from sklearn.metrics import accuracy_score
pred = model.predict(test) # sigmoid function에 의해 출력
print('test 분류 정확도 :', accuracy_score(test['RainTomorrow'], np.around(pred))) # 0.87272727
model.pred_table() : 분류 정확도 테이블 생성. logit()에서 지원. gim()은 지원하지않음.
from sklearn.metrics import accuracy_score
accuracy_score(실제값, np.around(예측값)) : 정확도 산출
verginica, setosa + versicolor로 분리해 구분 결정간격 시각화
* logistic3.py
from sklearn import datasets
from sklearn.linear_model import LogisticRegression
import numpy as np
iris = datasets.load_iris()
print(iris)
print(iris.keys())
# dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename'])
print(iris.target)
x = iris['data'][:, 3:] # petal width로 실습
print(x[:5])
# [0.2 0.2 0.2 0.2 0.2]
y = (iris['target'] == 2).astype(np.int)
print(y[:5])
# [0 0 0 0 0]
print()
log_reg = LogisticRegression().fit(x,y) # 모델생성
print(log_reg)
x_new = np.linspace(0, 3, 1000).reshape(-1,1) # 0 ~ 3 사이 1000개의 난수 발생
print(x_new.shape) # (1000, 1)
y_proba = log_reg.predict_proba(x_new) # 확률값
print(y_proba)
'''
[[9.99250016e-01 7.49984089e-04]
[9.99240201e-01 7.59799387e-04] ...
'''
import matplotlib.pyplot as plt
plt.plot(x_new, y_proba[:, 1], 'r-', label='verginica')
plt.plot(x_new, y_proba[:, 0], 'b--', label='setosa + versicolor')
plt.xlabel('petal width')
plt.legend()
plt.show()
print(log_reg.predict([[1.5],[1.7]])) # [0 1]
print(log_reg.predict([[2.5],[0.7]])) # [1 0]
print(log_reg.predict_proba([[2.5],[0.7]])) # [[0.02563061 0.97436939] [0.98465572 0.01534428]]
LogisticRegression으로 iris의 꽃의 종류를 분류
* logistic4
from sklearn import datasets
from sklearn.linear_model import LogisticRegression
import numpy as np
from sklearn.model_selection._split import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.preprocessing import StandardScaler, MinMaxScaler
import pandas as pd
iris = datasets.load_iris()
print(iris.data[:3])
'''
[[5.1 3.5 1.4 0.2]
[4.9 3. 1.4 0.2]
[4.7 3.2 1.3 0.2]]
'''
print(np.corrcoef(iris.data[:, 2], iris.data[:, 3]))
x = iris.data[:, [2, 3]] # feature(독립변수, x) : petal length, petal width
y = iris.target # label, class
print(type(x), type(y), x.shape, y.shape) # ndarray, ndarray (150, 2) (150,)
print(set(y)) # {0, 1, 2}
- train / test 분리
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.3, random_state=0)
print(x_train.shape, x_test.shape, y_train.shape, y_test.shape) # (105, 2) (45, 2) (105,) (45,)
- scaling(표준화 : 단위가 다른 feature가 두개 이상인 경우 표준화를 진행하여 모델의 성능을 향상시킨다)
print(x_train[:3])
'''
[[3.5 1. ]
[5.5 1.8]
[5.7 2.5]]
'''
sc = StandardScaler()
sc.fit(x_train)
sc.fit(x_test)
x_train = sc.transform(x_train)
x_test = sc.transform(x_test)
print(x_train[:3])
'''
[[-0.05624622 -0.18650096]
[ 1.14902997 0.93250481]
[ 1.26955759 1.91163486]]
'''
# 표준화 값을 원래 값으로 복귀
# inver_x_train = sc.inverse_transform(x_train)
# print(inver_x_train[:3])
- 분류 모델
: logit(), glm() : 이항분류 - 활성화 함수 - sigmoid : 출력 값이 0.5 기준으로 크고 작음에 따라 1, 2로 변경
: LogisticRegression : 다항분류 - 활성화 함수 - softmax : 복수의 확률값 중 가장 큰 값을 채택
model = LogisticRegression(C=1.0, random_state = 0) # C속성 : 모델에 패널티를 적용(L2 정규화) - 과적합 방지
model.fit(x_train, y_train) # 지도학습
- 분류 예측
y_pred = model.predict(x_test) # 검정자료는 test
print('예측값 :', y_pred)
print('실제값 :', y_test)
- 분류 정확도
print('총 개수 : %d, 오류수:%d'%(len(y_test), (y_test != y_pred).sum())) # 총 개수 : 45, 오류수:2
print('분류 정확도 출력 1: %.3f'%accuracy_score(y_test, y_pred)) # 분류 정확도 출력 1: 0.956
con_mat = pd.crosstab(y_test, y_pred, rownames = ['예측치'], colnames=['실제치'])
print(con_mat)
'''
실제치 0 1 2
예측치
0 16 0 0
1 0 17 1
2 0 1 10
'''
print('분류 정확도 출력 2:', (con_mat[0][0] + con_mat[1][1] + con_mat[2][2]) / len(y_test))
# 분류 정확도 출력 2: 0.9555555555555556
print('분류 정확도 출력 3:', model.score(x_test, y_test)) # test
# 분류 정확도 출력 3: 0.9555555555555556
print('분류 정확도 출력 3:', model.score(x_train, y_train)) # train
# 분류 정확도 출력 3: 0.9523809523809523
- 새로운 값으로 예측
new_data = np.array([[5.1, 2.4], [1.1, 1.4], [8.1, 8.4]])
# 표준화
sc.fit(new_data)
new_data = sc.transform(new_data)
new_pred = model.predict(new_data)
print('새로운 값으로 예측 :', new_pred) # [1 0 2]
- 붓꽃 자료에 대한 로지스틱 회귀 결과를 차트로 그리기
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from matplotlib import font_manager, rc
plt.rc('font', family='malgun gothic')
plt.rcParams['axes.unicode_minus']= False
def plot_decision_region(X, y, classifier, test_idx=None, resolution=0.02, title=''):
markers = ('s', 'x', 'o', '^', 'v') # 점 표시 모양 5개 정의
colors = ('r', 'b', 'lightgreen', 'gray', 'cyan')
cmap = ListedColormap(colors[:len(np.unique(y))])
#print('cmap : ', cmap.colors[0], cmap.colors[1], cmap.colors[2])
# decision surface 그리기
x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
x2_min, x2_max = X[:, 0].min() - 1, X[:, 0].max() + 1
xx, yy = np.meshgrid(np.arange(x1_min, x1_max, resolution), np.arange(x2_min, x2_max, resolution))
# xx, yy를 ravel()를 이용해 1차원 배열로 만든 후 전치행렬로 변환하여 퍼셉트론 분류기의
# predict()의 인자로 입력하여 계산된 예측값을 Z로 둔다.
Z = classifier.predict(np.array([xx.ravel(), yy.ravel()]).T)
Z = Z.reshape(xx.shape) # Z를 reshape()을 이용해 원래 배열 모양으로 복원한다.
# X를 xx, yy가 축인 그래프 상에 cmap을 이용해 등고선을 그림
plt.contourf(xx, yy, Z, alpha=0.5, cmap=cmap)
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
X_test = X[test_idx, :]
for idx, cl in enumerate(np.unique(y)):
plt.scatter(x=X[y==cl, 0], y=X[y==cl, 1], c=cmap(idx), marker=markers[idx], label=cl)
if test_idx:
X_test = X[test_idx, :]
plt.scatter(X_test[:, 0], X_test[:, 1], c=[], linewidth=1, marker='o', s=80, label='testset')
plt.xlabel('꽃잎 길이')
plt.ylabel('꽃잎 너비')
plt.legend(loc=2)
plt.title(title)
plt.show()
x_combined_std = np.vstack((x_train, x_test))
y_combined = np.hstack((y_train, y_test))
plot_decision_region(X=x_combined_std, y=y_combined, classifier=model, test_idx=range(105, 150), title='scikit-learn제공')
- 정규화
- 표준화
ROC curve
: 분류모델 성능 평가
* logistic5.py
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
import numpy as np
import pandas as pd
x, y = make_classification(n_samples=16, n_features=2, n_informative=2, n_redundant=0, random_state=12)
# : dataset
# n_samples : 표준 데이터수, n_features : 독립변수 수
print(x)
'''
[[-1.03701295 -0.8840986 ]
[-1.181542 1.35572706]
[-1.57888668 -0.13665031]
[-2.04426219 0.79930258]
[-1.42777756 0.2448902 ]
[ 1.26492389 1.54672358]
[ 2.53102266 1.99835068]
[-1.66485782 0.71855249]
[ 0.96918839 -1.25885923]
[-3.23328615 1.58405095]
[ 1.79298809 1.77564192]
[ 1.34738938 0.66463162]
[-0.35655805 0.33163742]
[ 1.39723888 1.23611398]
[ 0.93616267 -1.36918874]
[ 0.69830946 -2.46962002]]
'''
print(y)
# [0 1 0 0 1 1 1 0 0 1 1 0 1 1 0 0]
model = LogisticRegression().fit(x, y) # 모델
y_hat = model.predict(x) # 예측
print(y_hat)
# [0 1 0 1 0 1 1 1 0 1 1 1 0 1 0 0]
f_value = model.decision_function(x)
# 결정/판별/불확실성 추정 합수. ROC curve의 판별 경계선 설정을 위한 sample data 제공
print(f_value)
'''
[ 0.37829565 1.6336573 -1.42938156 1.21967832 2.06504666 -4.11896895
-1.04677034 -1.21469968 1.62496692 -0.43866584 -0.92693183 -0.76588836
0.09428499 1.62617134 -2.08158634 2.36316277]
'''
df = pd.DataFrame(np.vstack([f_value, y_hat, y]).T, columns= ['f', 'y_hat', 'y'])
df.sort_values("f", ascending=False).reset_index(drop=True)
print(df)
'''
f y_hat y
0 -1.902803 0.0 0.0
1 1.000982 1.0 1.0
2 -1.008356 0.0 0.0
3 0.143868 1.0 0.0
4 -0.487168 0.0 1.0
5 1.620022 1.0 1.0
6 2.401185 1.0 1.0 ...
'''
# ROC
from sklearn.metrics import confusion_matrix
print(confusion_matrix(y, y_hat, labels=[1, 0]))
# [[6 2]
# [3 5]]
accuracy = (6 + 5) / (6 + 2 + 3 + 5)
print('accuracy : ', accuracy) # accuracy : 0.6875
recall = 6 / (6 + 3) # 재현율 TPR
print('recall : ', recall) # recall : 0.6666666666666666
fallout = 3 / (3 + 5) # 위 양선율 FPR
print('fallout : ', fallout) # fallout : 0.375
from sklearn import metrics
acc_sco = metrics.accuracy_score(y, y_hat)
cl_rep = metrics.classification_report(y, y_hat)
print('acc_sco : ', acc_sco) # acc_sco : 0.6875
print('cl_rep : \n', cl_rep)
'''
precision recall f1-score support
0 0.71 0.62 0.67 8
1 0.67 0.75 0.71 8
accuracy 0.69 16
macro avg 0.69 0.69 0.69 16
weighted avg 0.69 0.69 0.69 16
'''
from sklearn.metrics import roc_curve
fpr, tpr, thresholds = roc_curve(y, model.decision_function(x))
print('fpr :', fpr) # fpr : [0. 0. 0. 0.375 0.375 1. ]
print('tpr :', tpr) # tpr : [0. 0.125 0.75 0.75 1. 1. ]
print('thresholds', thresholds) # thresholds [ 3.40118546 2.40118546 0.98927765 0.09570707 -0.48716822 -3.71164276]
import matplotlib.pyplot as plt
plt.plot(fpr, tpr, 'o-', label='Logistic Regression')
plt.plot([0, 1], [0, 1], 'k--', label='random guess')
plt.plot([fallout], [recall], 'ro', ms=10)
plt.xlabel('FPR')
plt.ylabel('TPR')
plt.title('ROC')
plt.show()
# AUC (Area Under the Curve) : ROC 커브의 면적
from sklearn.metrics import auc
print('auc :', auc(fpr, tpr)) # auc : 0.90625
'BACK END > Deep Learning' 카테고리의 다른 글
[딥러닝] PCA (0) | 2021.03.16 |
---|---|
[딥러닝] SVM (0) | 2021.03.16 |
[딥러닝] 다항회귀 (0) | 2021.03.12 |
[딥러닝] 단순선형 회귀, 다중선형 회귀 (0) | 2021.03.11 |
[딥러닝] 선형회귀 (0) | 2021.03.10 |