본문 바로가기
AI/Machine Learning

[ML] KNN - bmi model

by 안녕나는현서 2021. 4. 29.
728x90

<bmi model : 500명의 키와 몸무게, 비만도 라벨을 이용해 비만을 판단하는 모델을 만들어보자>

import pandas as pd
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsClassifier
from sklearn import metrics
from sklearn.metrics import classification_report
# 한글폰트 설정

from matplotlib import font_manager, rc
font_name = font_manager.FontProperties(fname='C:/Windows/Fonts/malgun.ttf').get_name()
rc('font', family=font_name)

 

- Data Collection

bmi = pd.read_csv('./bmi_500.csv') # ./는 현재 디렉토리를 뜻함

 

- 데이터 살펴보기

bmi.head() # 상위 5개 출력

bmi.tail() # 하위 5개 출력

# Label이 정상(Normal)인 리스트 출력

bmi_idx = bmi['Label']=='Normal'
bmi[bmi_idx]

bmi.info()

bmi.describe()

# Label의 중복을 제거한 리스트 출력

bmi['Label'].unique()

# 각 비만도 등급별로 시각화(산점도 - scatter plot)

def myScatter(label, color) :
    tempMask = bmi['Label']==label
    temp = bmi[tempMask]
    plt.scatter(temp['Weight'], temp['Height'], c=color, label=label)
    
plt.figure(figsize=(5,5))

myScatter('Extremely Weak' , 'black')
myScatter('Weak'           , 'blue')
myScatter('Normal'         , 'green')
myScatter('Overweight'     , 'pink')
myScatter('Obesity'        , 'purple')
myScatter('Extreme Obesity', 'red')

plt.legend(loc='upper right')
plt.xlabel('Weight')
plt.ylabel('Height')
plt.show()

 

- Data Preparation

# Height와 Weight를 feature로 설정하여 문제/답 데이터 분리

X = bmi.loc[:, 'Height':'Weight']
y = bmi.loc[:, 'Label']
# 훈련/검증 데이터 분리

X_train = X.loc[:349]
y_train = y.loc[:349]
X_test = X.loc[350:]
y_test = y.loc[350:]

 

- Choose a model

knn_model = KNeighborsClassifier(n_neighbors = 10)

 

- Train the model

knn_model.fit(X_train, y_train)

 

- Evaluate the model

# 검증데이터셋을 모델에 적용한 결과 

pred_test = knn_model.predict(X_test)

# 검증데이터셋과 실제데이터셋을 비교하여 모델 평가

metrics.accuracy_score(pred_test, y_test)

# 과대/과소적합 확인
# 우리가 만든 훈련스코어와 검증 스코어를 도출하여 훈련/검증의 효율성 분석

pred_train = knn_model.predict(X_train)
metrics.accuracy_score(pred_train, y_train)

print(classification_report(pred_train, y_train))

# Score()함수 사용

knn_model.score(X_test, y_test)

knn_model.score(X_train, y_train)

 

- Hyperparameter tuning

# 훈련데이터와 검증데이터의 스코어 차이가 많이 나지 않을 경우,
# 데이터에 굉장히 특화되어있을 경우 많음(과대적합)

# hyperparameter tuning을 위하여 n_neighbors 값을 1부터 10까지 적용해보고
# score값을 비교하는 그래프 출력하는 함수 만들기

def H_tuning (Xtrain, ytrain, Xtest, ytest) :
    train_acc = []
    test_acc = []
    neighbor = range(1,11)
    
    for n in neighbor :
        knn_model = KNeighborsClassifier(n_neighbors = n)
        knn_model.fit(Xtrain, ytrain)
        
        train_acc.append(knn_model.score(Xtrain, ytrain))
        test_acc.append(knn_model.score(Xtest, ytest))
    
    plt.plot(neighbor, train_acc, label = 'Train_acc')
    plt.plot(neighbor, test_acc, label = 'Test_acc')
    plt.legend(loc = 'best')
    plt.xlabel('n_neighbors')
    plt.ylabel('Acc')
# 차트 그리기

H_tuning(X_train, y_train, X_test, y_test)

  • 차트 확인 결과
    • 차트를 확인해보면 튀는 값들이 있음
    • 검증데이터의 스코어가 훈련데이터보다 뛰어넘었을 경우는 과소적합
    • 따라서 데이터의 '성별'이라는 특성을 추가하여 분석을 시도해보자

 

- Data Collection

bmi2 = pd.read_csv('./bmi_500.csv')

 

- Data Preparation

# '성별'특성의 데이터를 수치형으로 변환

bmi2['Gender'] = bmi2['Gender'].map({'Male':0, 'Female':1})
bmi2

# 문제/답 데이터 분리

X2 = bmi2.loc[:, :'Weight']
y2 = bmi2.loc[:, 'Label']
# 훈련/검증 데이터 분리

X_train2 = X2.loc[:349]
y_train2 = y2.loc[:349]
X_test2 = X2.loc[350:]
y_test2 = y2.loc[350:]

 

- Choose a model

knn_model = KNeighborsClassifier(n_neighbors = 10)

 

- Train the model

knn_model.fit(X_train2, y_train2)

 

- Evaluate the model

knn_model.score(X_train2, y_train2)

knn_model.score(X_test2, y_test2)

 

- Hyperparameter tuning

# 튜닝값을 조정하는 차트를 그려서 초기차트와 비교

plt.figure(figsize=[20,7])

plt.subplot(1, 2, 1)
H_tuning(X_train, y_train, X_test, y_test)
plt.title('성별 특성 추가 전')

plt.subplot(1, 2, 2)
H_tuning(X_train2, y_train2, X_test2, y_test2)
plt.title('성별 특성 추가 후')

plt.show()

  • 차트 확인 결과
    • 튀는 값들이 조금 보정되었지만 여전히 있음
    • 따라서 데이터에 새로운 특성을 추출하여 분석을 시도해보자

 

- Data Preparation

# 새로운 특성(컬럼간의 곱) 추가

X_train3 = X_train.copy()
col = X_train3.columns

for i in range(col.size) :
    for j in range(i, col.size) :
        X_train3[col[i]+'x'+col[j]] = X_train3[col[i]] * X_train3[col[j]]
        
X_train3.head()

# 검증데이터도 마찬가지로 새로운 특성 추가

X_test3 = X_test.copy()
col = X_test3.columns

for i in range(col.size) :
    for j in range(i, col.size) :
        X_test3[col[i]+'x'+col[j]] = X_test3[col[i]] * X_test3[col[j]]
        
X_test3.head()

 

- Choose a model

knn_model = KNeighborsClassifier(n_neighbors = 10)

 

- Train the model

knn_model.fit(X_train3, y_train)

 

- Evaluate the model

knn_model.score(X_train3, y_train)

knn_model.score(X_test3, y_test)

 

- Hyperparameter tuning

# 튜닝값을 조정하는 차트를 그려서 앞의 차트들과 비교

plt.figure(figsize=[20,7])

plt.subplot(1, 3, 1)
H_tuning(X_train, y_train, X_test, y_test)
plt.title('키,몸무게 특성만 적용')

plt.subplot(1, 3, 2)
H_tuning(X_train2, y_train2, X_test2, y_test2)
plt.title('성별 특성 추가 후')

plt.subplot(1, 3, 3)
H_tuning(X_train3, y_train, X_test3, y_test)
plt.title('특성간의 곱 추가 후')

plt.show()

728x90

댓글