ML - 8. (분류)Logistic Regression - PIMA 인디언 당뇨병 예측

jaam._.mini·2024년 1월 23일
0

Logistic Regression을 쓰는 이유 : 💡분류기 역할

즉, linear regression (선형회귀)을 분류에 적용한 것이 Logistic Regression (로지스틱 회귀)이다.



LR 이론


악성 종양을 찾는다고 가정하자.
linear regression (선형회귀)에 적용한다면 0과 1밖에 없어서 수 많은 데이터를 분류하기가 어려 움.
보이지 않는 데이터가 멀-리 있다면 확인이 어려움

출력이 0과 1사이에 위치하게 하는 [시그모이드]에 linear regression() 함수를 넣으면 = "직선"이 됨

📌 sigmoid (function)

기울어진 S자 형태의 곡선

linear regression에서 sigmoid를 재정의

import numpy as np
import matplotlib.pyplot as plt

# np의 arrange 명령으로 (-10 ~ 10 까지, 0.01 간격)
z = np.arange(-10,10,0.01)
g = 1/(1+np.exp(-z))

plt.plot(z,g);
  • 그래프 멋내기

    import numpy as np
    import matplotlib.pyplot as plt
    
    plt.figure(figsize=(10,8))
    ax = plt.gca()
    
    ax.plot(z,g)
    ax.spines['left'].set_position('zero')
    ax.spines['bottom'].set_position('center')
    ax.spines['right'].set_color('none')
    ax.spines['top'].set_color('none')

📌 Cost Function (funtion)

Logistic Regression에서 Cost Function을 재정의

  • 
    c0 = -np.log(1-h)
    c1 = -np.log(h)
    
    plt.figure(figsize=(7,3))
    plt.plot(h, c0, label='y=0')
    plt.plot(h, c1, label='y=1')
    plt.legend()
    
    plt.show()
    






와인 분석


1) 데이터 가져오기

import pandas as pd

wine_url = 'https://raw.githubusercontent.com/PinkWink/ML_tutorial/master/dataset/wine.csv'
wine = pd.read_csv(wine_url,index_col=0)
wine.head()

2) 맛 등급 설정

# (1) quality 컬럼 이진화
# wine 데이터의 ['taste'] 컬럼 생성
# wine의 quality column울 grade로 잡고, 5등급 보다 크면 1, 그게 아니라면 0으로 잡음
wine['taste'] = [1. if grade>5 else 0. for grade in wine['quality']]



# (2) 모델링
# label인 taste, quality를 drop, 나머지를 X의 특성으로 봄
X = wine.drop(['taste', 'quality'], axis=1)

# 새로만들 y데이터
y = wine['taste']

3) 데이터 분리

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=13)

4) 로지스틱 회귀

# 분류기
from sklearn.linear_model import LogisticRegression

# 성능
from sklearn.metrics import accuracy_score

# solver(최적화 알고리즘) = liblinear(데이터 수가 작으면 보통 이걸로 선택)
lr = LogisticRegression(solver='liblinear', random_state=13)

# 학습 (train, train)
lr.fit(X_train, y_train)

# 예측 = 학습이 완료된 lr에게 시킴
y_pred_tr = lr.predict(X_train)
y_pred_test = lr.predict(X_test)

# 성능 확인
print('Train Acc :', accuracy_score(y_train, y_pred_tr))
print('Test Acc :', accuracy_score(y_test, y_pred_test))

Train Acc : 0.7429286126611506
Test Acc : 0.7446153846153846

5) 파이프라인 구축 (스케일러 적용)

# Pipeline
from sklearn.pipeline import Pipeline
# StandardScaler
from sklearn.preprocessing import StandardScaler

# 평가 변수
estimators = [
    # 표준화(scaler)
    ('scaler', StandardScaler()),
    # 분류기(clf)
    ('clf', LogisticRegression(solver='liblinear', random_state=13))
]

pipe = Pipeline(estimators)

6) 학습, 예측, 성능 확인

# 학습
pipe.fit(X_train, y_train)

# 예측 = 학습이 완료된 lr에게 시킴
y_pred_tr = pipe.predict(X_train)
y_pred_test = pipe.predict(X_test)

# 성능 확인
print('Train Acc :', accuracy_score(y_train, y_pred_tr))
print('Test Acc :', accuracy_score(y_test, y_pred_test))

Train Acc : 0.7444679622859341
Test Acc : 0.7469230769230769

7) Decision Tree와 비교

from sklearn.tree import DecisionTreeClassifier

wine_tree = DecisionTreeClassifier(max_depth=2, random_state=13)
wine_tree.fit(X_train, y_train)

models = {'LogisticRegression' : pipe, 'DecisionTree' : wine_tree}

8) AUC 그래프로 비교 확인

  • thresholds(임계값) 보다 크면 양성, 작으면 음성
  • 모델은 분류에서 확률(0~1) 또는 음수~양수 사이의 실수를 예측값으로 출력
  • sklearn에서는 predict_proba을 제공
  • predict_proba : 0.5 이상이면 1로 예측
# roc_curve
from sklearn.metrics import roc_curve

plt.figure(figsize=(10,8))
plt.plot([0,1], [0,1])

# model_name : LogisticRegression, DecisionTree
# model : pipe, wine_tree
for model_name, model in models.items():
    # 첫번째 커럼은 0일 확률, 두번쨰 컬럼은 1일 확률이라서 [:, 1]
    # predict_proba : 0.5 이상이면 1로 예측
    pred = model.predict_proba(X_test)[:, 1]
    # roc_curve의 thresholds (임계값)
    fpr, tpr, thresholds = roc_curve(y_test, pred)
    plt.plot(fpr, tpr, label=model_name)

plt.grid()
plt.legend()
plt.show()

LogisticRegression의 결과가 더 좋은 것으로 확인 됨






PIMA 인디언 당뇨병 예측 분석


1) 데이터 가져오기

import pandas as pd

PIMA_url = 'https://raw.githubusercontent.com/PinkWink/ML_tutorial/master/dataset/diabetes.csv'
PIMA = pd.read_csv(PIMA_url)
PIMA.head()

2) 데이터 확인

PIMA.info()

3) 데이터 전부 float 으로 변환 (astype)

PIMA = PIMA.astype('float')
PIMA.info()

4) 상관관계 확인

import seaborn as sns
import matplotlib.pyplot as plt

plt.figure(figsize=(6,4))

# PIMA.corr() : PIMA의 상관계수()
sns.heatmap(PIMA.corr(), cmap='YlGnBu')
plt.show()

5) 0인 데이터 확인 - 이상한 값들이 있는지 보기 위해

# (PIMA==0) : 0이 있는지 확인, T/F로 뜸
# (PIMA==0).astype(int) : T=1, F=0
# (PIMA==0).astype(int).sum() : 컬럼별로 0이 몇개 있는지 나옴
(PIMA== 0).astype(int).sum()

⭐ 이상한 값(결측치) 해결

6) 이상한 값들은 평균값으로 대체 (replace)

# - 혈압(BloodPressure)은 0일수 없다...

zero_features = ['Glucose', 'BloodPressure', 'SkinThickness', 'BMI']
PIMA[zero_features] = PIMA[zero_features].replace(0, PIMA[zero_features].mean())

7) 데이터 분리

X = PIMA.drop(['Outcome'], axis=1)
y = PIMA['Outcome']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,
                                                    random_state=13, stratify=y)
                                                    
estimators = [('scaler', StandardScaler()),
               ('clf', LogisticRegression(solver='liblinear', random_state=13))]
pipe_lr = Pipeline(estimators)
pipe_lr.fit(X_train, y_train)
pred = pipe_lr.predict(X_test)

8) 수치 확인

from sklearn.metrics import (accuracy_score, recall_score, precision_score,
                             roc_auc_score, f1_score)

print(accuracy_score(y_test, pred))
print(recall_score(y_test, pred))
print(precision_score(y_test, pred))
print(roc_auc_score(y_test, pred))
print(f1_score(y_test, pred))

9) 다변수 방정식의 각 계수 값 확인

coeff = list(pipe_lr['clf'].coef_[0])
labels = list(X_train.columns)

10) feature 그리기

# DataFrame
features = pd.DataFrame({'Features': labels, 'importance': coeff})
features.sort_values(by=['importance'], ascending=True, inplace=True)

# positive 생성
features['positive'] = features['importance'] > 0
features.set_index('Features', inplace=True)

# importance 를 그릴 것
features['importance'].plot(kind='barh', figsize=(11, 6),
                            color=features['positive'].map({True: 'blue', False: 'red'}))
plt.xlabel('Importance')
plt.show()
profile
비전공자의 데이터 공부법

0개의 댓글