qcoding

[데이터분석실습][이진분류_결정트리]소득 예측 모델 만들기 본문

Python 데이터분석

[데이터분석실습][이진분류_결정트리]소득 예측 모델 만들기

Qcoding 2022. 6. 28. 14:59
반응형

https://github.com/youngwoos/Doit_Python/tree/main/Data

 

GitHub - youngwoos/Doit_Python: <Do it! 쉽게 배우는 파이썬 데이터 분석> 저장소

<Do it! 쉽게 배우는 파이썬 데이터 분석> 저장소. Contribute to youngwoos/Doit_Python development by creating an account on GitHub.

github.com

## 소득예측 모델 만들기

import pandas as pd
import numpy as np
import seaborn as sns

df=pd.read_csv('./adult.csv')
df

 

 

변수명 의미
age 나이
workclass 근로 형태
fnlwgt 인구통계 가중치
education 최종학력
education_num 교육기간
marital_status 결혼상태
occupation 직종
relationship 가구주와의 관계
race 인종
sex 성별
capital_gain 자본소득(USD)
capital_loss 자본손실(USD)
hours_per_week 주당 근무시간
native_country 출신국가
income 연소득

 

# 전처리

1) 타켓변수 전처리

## 데이터 전처리
# 타켓변수 전처리
# nomarlize = True 시 범주의 비율을 계산함

df['income'].value_counts( normalize = True)

# >50k 경우를 high 그렇지 않은 경우를 low로 변경함
df['income']=np.where(df['income']== ">50K" , "high" ,"low")
df['income'].value_counts( normalize = True)

2) 필요없는 변수 제거

df=df.drop(columns=['fnlwgt'])
df

 

3) 문자 타입 변수를 숫자 타입으로 바꾸기

-> One-hot encoding 을 사용하여 문자 타입 변수를 숫자 타입으로 변함

## one-hot 인코딩을 하기 위하여 target 제외 후 다시 합침
target=df['income']

df=df.drop(columns=['income'])
df
# one-hot encoding 진행
df=pd.get_dummies(df)
df['income']=target

# info() 옵션은 변수가 100개 이하일때만 변수 정보가 출력되므로, max_cols=np.inf 옵션을 사용
df.info(max_cols=np.inf)

 

 

# 데이터 분할하기

-> Train / Test set 분리

## 데이터 분할하기
from sklearn.model_selection import train_test_split

df_train, df_test=train_test_split(
    df,
    test_size=0.3,
    #타켓 변수 비율 유지
    stratify=df['income'],
    random_state=1234
)

print("train" , df_train.shape)
print("test", df_test.shape)

# 위에서 data split 시에 stratify 옵션을 통해서 타켓 비율을 유지하였음

# 비율유지 확인
train=df_train['income'].value_counts(normalize=True)
print("train\n",train)
print("-----------------------")

test=df_test['income'].value_counts(normalize=True)
print("test\n",test)

# 모델 설정하기

# 모델 설정하기
from sklearn import tree

clf=tree.DecisionTreeClassifier(random_state=1234, max_depth=3)

# 모델 만들기
x_train=df_train.drop(columns=['income'])
y_train=df_train['income']

model=clf.fit(x_train,y_train)
model

# 모델 구조 시각화하기

#시각화
import matplotlib.pyplot as plt
plt.rcParams.update({
    'figure.figsize' :[12,8],
    'figure.dpi' :'100'
})


tree.plot_tree(model);

# 그래프 수정

# 그래프 수정
tree.plot_tree(model,
              #  예측 변수명
              feature_names=x_train.columns,
              #  target 변수 클래스, 알파벳순
               class_names=["high","low"],
              #  비율표기,
               proportion=True,
               filled=True,
               rounded=True,
              #  불순도 표시
               impurity=False,
              # label표시위치
               label='root',
               fontsize=10
                 
            );

# 그래프해석

1) 맨위의 marital ... 은 조건으로 One-hot encoding을 통해 만들어진 변수임. 0(미혼) , 1(기혼)으로 전체 샘플의 100%를 놓고 가장 크게 나눌 수 있는 조건이 됨.

 

2) value=[0.239 , 0.761] 의 의미는 target변수의 비율로 "high " , "low" 알파벳순서로 나타내며, 전체 100% 중 low의 비율이 76.1% 가 된다는 의미이다.

 

3) class는 우세한 class의 종류를 나타내므로, 앞에서 low의 비율이 우세하므로 low일 확률 이 높다는 것이다.

 

1) 두번 째 node를 보면 왼쪽은 미혼(0) 이고 오른쪽은 기혼(1)로 나뉘어져 있다.

 

2) 왼쪽에서 미혼(0) 의 경우는 전체의 54.2%에 해당되며, value=[0.064, 0.936] 으로 low일 확률이 93.6%가 된다.

색이 짙을 수록 비율이 높다는 것을 의미한다.

 

3) 오른쪽에서는 비혼(1)의 경우는 전체의 45.8%에 해당되며, value=[0.447 , 0.553] 으로 거의 비슷하지만 low일 확률이 55.3%더 높으므로 low에 해당하고 색은 옅은 편이다.

 

# 모델 예측하기

# 모델 예측하기
x_test=df_test.drop(columns=['income'])
y_test=df_test['income']

df_test['pred']=model.predict(x_test)
df_test[['income','pred']]

 

 

# 평가하기

# confusion matrix 만들기
from sklearn.metrics import confusion_matrix

conf_mat=confusion_matrix(
    y_true=df_test['income'],
    y_pred=df_test['pred'],
    labels=['high','low']
)
conf_mat

## confusion mastirx heat map 사용하기

#그래프 설정 되돌리기
plt.rcParams.update(plt.rcParamsDefault)


from sklearn.metrics import ConfusionMatrixDisplay
p=ConfusionMatrixDisplay(
    confusion_matrix=conf_mat,
    display_labels=('high' , 'low')
)
p.plot(cmap='Blues')

# 성능지표 

1) Accuracy (정확도)


-> 예측해서 맞춘 비율로 (TP + TN) / 전체합산

import sklearn.metrics as metrics

metrics.accuracy_score(
    y_true=df_test['income'],
    y_pred=df_test['pred']
)

-> 기본적으로 자료에서 low인 사람이 76%로 매우 많았기 때문에, 항상 low만 말하는 모델을 만든다면 적어도 76% 확률은 될 것 이므로 accuracy만 보아서는 안된다.

 

2)Precision (정밀도)

-> Positive라고 해서 실제 맞춘비율

-> TP  / (TP +FP)

metrics.precision_score(
    y_true=df_test['income'],
    y_pred=df_test['pred'],
    # 관심 클래스
    pos_label='high'
)

-> 소득을 high라고 예측한 사람 중에 75%가 high 이고 나머지는 low인데 high라고 말하였다.

 

3) Recall (재현율)

-> 실제 데이터가 Positive인 경우에서 내가 Positive라고 해서 맞은 확률

-> TP / (TP+FN)

metrics.recall_score(
    y_true=df_test['income'],
    y_pred=df_test['pred'],
    # 관심 클래스
    pos_label='high'
)

-> 실제로 소득이 'high' 인 사람에서 51.3%를 'high' 라고 찾아냈고, 나머지 48.7%는 'low'라고 예측을 해서 틀리 경우이다.

 

4) F1 socre

-> recall 과 precision의 조화평균 , 성능이 좋을 수록 1이 됨.

metrics.f1_score(
    y_true=df_test['income'],
    y_pred=df_test['pred'],
    # 관심 클래스
    pos_label='high'
)

 

 

# 어떤 지표를 사용해야 되는가

1) precision : 관심 클래스가 분명할때 // 관심 클래스로 예측해서 틀릴때 손실이 더 클때

-> 모델을 사용하는 목적이 타멧 변수의 클래스 중에서 관심을 두는 한쪽 클래스를 정확하게 예측하는 것일때

-> 구매 가능성이 낮은 저소득자에게 값비싼 선물을 보내는 손실이 구매할 가능성이 있는 고소득자에게 선물을 보내지 않는 것보다 손실이 크므로, 고소득자라고 예측하는 것이 분명해야 할 때

--> 'Positive' 라고 말해서 틀리는 확률을 줄여야 할 때 , FP를 줄어야 할때

 

 

2) recall :관심 클래스를 최대한 많이 찾아내야 할때  // 관심 클래스를 놓칠 때 손실이 더 클 때

-> 모델을 사용하는 목적이 관심 클래스를 최대한 많이 찾아 내는 것 일 때

-> 전염병에 걸린 사람을 찾지 못해서 전염병이 확산되는 것이 정상인 환자를 격리하는 것보다 손실이 더 클 때

-> 'Negative' 라고 말해서 틀리는 확률을 줄여야 할 때, FN을 줄어야 할 때 

반응형
Comments