본문 바로가기
머신러닝/Logistic Regression

Logistic Regression - PIMA 인디언 당뇨병 예측

by 미생22 2024. 5. 7.
728x90

Logistic Regression은 분류를 위한 것으로 PIMA 인디언의 당뇨병을 예측하기 좋습니다.

PIMA 인디언은 1950년대까지 당뇨가 없었습니다. 그런데 20세기 말, 50%가 당뇨에 갑자기 걸렸고 50년만에 50%의 인구가 당뇨에 걸렸다고 합니다. 원래 데이터는 kaggle에 있는데 저희는 pinkwink에서 가져오겠습니다.

각 컬럼에 대한 정보는 다음과 같습니다.

 

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()

pima.info()

 

총 768개의 데이터가 있고 전부 수치형 데이터네요.
안전하게 데이터를 처리하기 위해 전부 float형태로 바꿔보겠습니다.

 

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

일단 상관관계를 확인해보겠습니다.

pima.corr()

 

이걸 heatmap으로 보기쉽게 그려볼게요

import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline #주피터 노트북에서 주로 쓰는 코드

plt.figure(figsize=(12, 10))
sns.heatmap(pima.corr(), annot=True, cmap='YlGnBu')
plt.show()

outcome과 관련있는 것들을 찾아보면 pregnancies, glucose, BMI, Age 정도가 있네요... 높은 수치는 아니지만...
그런데 0이 있습니다.

pima==0

 

여기서 중요한 0을 처리하는 방법이 있습니다.

(pima==0).astype(int) #이렇게하면 false는 0, true는 1이 됩니다.

이거를 sum시켜보겠습니다. 그러면 true의 갯수가 나오겠죠.

(pima==0).astype(int).sum()

 

 

(pima==0).astype(int).sum()

이 0은 null은 아니라서 위 코드가 생각보다 자주 쓰일겁니다.
그런데 혈압이 0인 데이터, 체지방 지수가 0인 데이터가 있다고합니다.
절대로 0이 될 수 없는 데이터를 가져와보겠습니다.
null값이라면 앞뒤 데이터의 중간값이나 부드럽게 넘어갈 수 있는 데이터로 가져오겠지만 0은 수치라서 상당히 힙듭니다.
특히 의학적 지식과 PIMA 인디언에 대한 정보가 없으므로 일단 평균값으로 대체하겠습니다.

 

zero_feature = ['Glucose', 'BloodPressure', 'SkinThickness', 'BMI']
pima[zero_feature] = pima[zero_feature].replace(0, pima[zero_feature].mean()) #이렇게하면 해당 열의 평균값으로 대체합니다.
(pima==0).astype(int).sum()

파이썬의 좋은점이죠. replace를 통해 0을 각 컬럼별 평균값으로 바꿀 수 있습니다. ㅎㅎ

이제 데이터를 나누겠습니다.

from sklearn.model_selection import train_test_split

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, 
                                                    #당뇨냐 아니냐에 대한 구조를 그대로 가져가라고 하겠습니다.
                                                    stratify=y,
                                                    random_state=13)

 

pipeline을 만들어주겠습니다.

 

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression

estimate = [
    ('scaler', StandardScaler()),
    ('clf', LogisticRegression(solver='liblinear', random_state=13))
]

pipe_lr = Pipeline(estimate)
pipe_lr.fit(X_train, y_train)
pred = pipe_lr.predict(X_test)

 

이제 model evaluation때 배웠던 수치들을 전부 확인해보겠습니다.

 

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

print('Accuracy : ', accuracy_score(y_test, pred))
print('Recall : ', recall_score(y_test, pred))
print('Precision : ', precision_score(y_test, pred))
print('AUC score : ', roc_auc_score(y_test, pred))
print('f1 score : ', f1_score(y_test, pred))

 

그러나 이 수치들은 수치 자체를 평가할 순 없습니다.
총 컬럼이 8개였으므로 x1 x2 x3, ..., x8 이고 theta1, theta2, ..., theta8으로 총 8개의 변수가 사용된겁니다.
어떤 변수가 가중치가 큰지 확인해보기 위해서 pipe_lr의 clf의 coef_를 확인해보겠습니다.

 

pipe_lr['clf'].coef_

list가 두개네요... [0]을 붙여서 때고 column이름을 붙여줘야겠습니다.

coef = list(pipe_lr['clf'].coef_[0])
label = list(X_train.columns)
coef

이제 중요한 feature에 대해 map으로 그려보겠습니다.

features = pd.DataFrame(columns=label, data=coef) 이건 안되네요..list는 열에만 넣어집니다.
importances 순으로 나열해보겠습니다.

 

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

그래프에 color을 입히기 위해 column을 만들어보겠습니다.

 

features['positive'] = features['importance']>0
features

그래프를 쉽게 보기위해 index를 설정하겠습니다.

features.set_index('Features', inplace=True)
features

이제 map을 그려보겠습니다.

features['importance'].plot(kind='barh',
                            figsize=(11,6),
                            color=features['positive'].map({True:'blue', False:'red'}) #barh에 color를 부여하기 위한 옵션입니다.
                            )
plt.xlabel('importance')
plt.show()

 

네, 포도당, BMI등은 당뇨에 영향을 미치는 정도가 높습니다.
혈압은 예측에 부정적인 영향을 줍니다.
연령이 BMI보다 출력 변수와 더 관련되어 있었지만, 모델은 BMI와 Glucose에 더 의존합니다.

728x90