머신러닝 기초 | 로지스틱 회귀로 와인 분류 | 결정트리 / 가지치기 | DecisionTreeClassifier 클래스 | plot_tree() 함수

728x90

 

1. 로지스틱 회귀로 와인 분류하기

 

1-1) wine 데이터 가져와서 데이터 전처리하기

: 입고된 와인을 보니 급하게 제작하는 바람에 레드 와인과 화이트 와인 표시가 누락된 상태.!.!.!
: 알코올 도수, 당도, pH 값에 로지스틱 회귀 모델을 적용할 계획

import pandas as pd

wine = pd.read_csv('https://bit.ly/wine-date')

: 6,497개의 와인 샘플 데이터를 확보
: 판다스를 사용해 인터넷에서 직접 읽어옴

 

▶ wine 데이터 확인

wine.head()

: 처음 3개의 열(alcohol, sugar, pH)은 각각 알코올 도수, 당도 pH 값을 나타냄
: 타깃 값은 레드 와인,이면 0, 화이트 와인이면 1로 지정
: 레드 와인과 화이트 와인을 구분하는 이진 분류문제. 화이트 와인이 양성 클래스(전체 와인 데이터에서 화이트 와인을 골라내는 문제)

 

▶ wine 데이터 정보 확인

: info() 함수로 데이터프레임의 각 열의 데이터 타입을 알아보고, 누락된 데이터가 있는지 확인

wine.info()

>> 총 6,497개의 샘플이 있고 4개의 열은 모두 실수값
>> Non-Null Count가 모두 6497이므로 누락된 값은 없는 것으로 보임

▶ wine 데이터 통계정보 확인

: 평균, 표준편차, 최소, 최대, 중간값(50%), 1사분위수(25%), 3사분위수(75%)
: 사분위수는 데이터를 순서대로 4등분 한 값

wine.describe()

 

▶ 판다스 데이터프레임을 넘파이 배열로 바꾸기 + 훈련/테스트 세트 나누기

data = wine[['alcohol', 'sugar', 'pH']].to_numpy()
target = wine['class'].to_numpy()

: wine 데이터프레임의 alcohol, sugar, pH 열을 넘파이 배열로 바꿔서 data 배열에 저장
: calss 열도 넘파이 배열로 바꿔서 target 배열에 저장

 

▶ train_test_split()

: train_test_split() 함수는 설정값을 지정하지 않으면 25%를 테스트 세트로 지정

: 매개변수 test_size로 샘플개수 비율 지정

: 샘플 개수가 충분히 많으므로 20% (0.2)정도만 테스트 세트로 나눔

from sklearn.model_selection import train_test_split

train_input, test_input, train_target, test_target = train_test_split(
    data, target, test_size=0.2, random_state=42)

 

▶ 훈련/테스트 세트 데이터 shape 확인해보기

print(train_input.shape, test_input.shape)

>> 훈련세트는 5,197개이고 테스트 세트는 1,300개

 

▶ 사이킷런  StandardScaler 클래스로 특성 표준화하기(데이터 전처리)

: 알코올 도수와 당도, pH 값의 스케일이 다 다름
: 사이킷런의 StandardScaler 클래스를 사용해 훈련 세트의 특성을 표준화

from sklearn.preprocessing import StandardScaler

ss = StandardScaler()
ss.fit(train_input)

train_scaled = ss.transform(train_input)
test_scaled = ss.transform(test_input)

: 객체는 그대로 사용해 테스트세트를 변환

 

 

1-2) 로지스틱 회귀로 와인 분류

 

▶ 표준점수로 변환된 train_scaled와 test_scaled로 로지스틱 회귀 모델을 훈련

from sklearn.linear_model import LogisticRegression

lr = LogisticRegression()
lr.fit(train_scaled, train_target)

print(lr.score(train_scaled, train_target))
print(lr.score(test_scaled, test_target))

>> 생각보다 화이트 와인을 골라내는 게 어려움
>> 훈련세트와 테스트 세트의 점수가 모두 낮으니 모델이 다소 과소적합

 

▶ 절편 값 구하는 방법

: 로지스틱 회귀가 학습한 계수와 절편

print(lr.coef_, lr.intercept_)

 

>> 알코올 도수와 당도가 높을수록 화이트 와인일 가능성이 높고,  pH가 높을수록 레드와인일 가능성이 높은 것 같음
>> 머신러닝 모델은 이렇게 학습결과를 설명하기 힘듦

 

 


2. 결정트리

▶ 결정트리

: 결정트리(Decision Tree)는 질문을 하나씩 던지고 정답과 맞추어 감
: 계속 질문을 추가해서 분류 정확도를 높일 수 있음
: 사이킷런의 DecisionTreeClassifier 클래스를 사용해 결정 트리모델을 훈련

 

▶ 사이킷런_DecisionTreeClassifier 클래스

from sklearn.tree import DecisionTreeClassifier

dt = DecisionTreeClassifier(random_state=42)
dt.fit(train_scaled, train_target)

print(dt.score(train_scaled, train_target))  # 훈련세트
print(dt.score(test_scaled, test_target))    # 테스트세트

 

>> 훈련세트에 대한 점수가 높음
>> 테스트세트의 성능은 그에 비해 조금 낮음(과대적합된 모델)

 

▶ plot_tree() 함수로 그림 그려보기

: 결정 트리 모델 객체를 plot_tree() 함수에 전달해 어떤 트리가 만들어졌는지 확인

: 루프 노드와 리프노드

import matplotlib.pyplot as plt
from sklearn.tree import plot_tree

plt.figure(figsize=(10,7))
plot_tree(dt)
plt.show()

 

* 매개변수 max_depth =

: 너무 복잡하니 plot_tree() 함수에서 트리의 깊이를 제한해서 출력
: max_depth 매개변수를 1로 주면 루트 노드를 제외하고 하나의 노드를 더 확장하여 그림
: filled 매개변수에서 클래스에 맞게 노드의 색을 칠할 수 있음
: featture_names 매개변수에는 특성의 이름을 전달할 수 있음

plt.figure(figsize=(10,7))
plot_tree(dt, max_depth=2, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()

 

* 루트노드 해석

>> 음성클래스(레드와인) 1,258개, 양성클래스(화이트와인) 3,939개 임

 


3. 가지치기

 

▶ 가지치기

: 결정트리 가지치기 하기

: 그렇지 않으면 무작정 끝까지 자라나는 트리가 만들어짐
: 훈련세트에는 아주 잘 맞겠지만 테스트세트 점수는 그리 좋지 않을 것
: 일반화가 잘 안되는 경향이 있음

 

▶ 가지치기하는 간단한 방법

: 매개변수 max_depth 설정하기

dt = DecisionTreeClassifier(max_depth=3, random_state=42)
dt.fit(train_scaled, train_target)

print(dt.score(train_scaled, train_target))
print(dt.score(test_scaled, test_target))

>> 훈련세트의 정확도는 낮아졌지만 테스트세트의 정확도는 거의 그대로임

 

▶ plot_tree() 함수로 그림 그려보기

plt.figure(figsize=(20,15))
plot_tree(dt, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()

 


 

▶ 전처리 하기 전의 훈련/테스트 세트 결정트리모델 다시 훈련해보기

: 전처리하기 전의 훈련세트(train_input)와 테스트세트(test_input)로 결정 트리 모델 다시 훈련

dt = DecisionTreeClassifier(max_depth=3, random_state=42)
dt.fit(train_input, train_target)

print(dt.score(train_input, train_target))
print(dt.score(test_input, test_target))

 

▶ plot_tree() 함수로 다시 그림 그려보기

plt.figure(figsize=(20,15))
plot_tree(dt, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()

 

>> 결과를 보면 같은 트리지만, 특성값을 표준점수로 바꾸지 않은 트리가 이해하기가 쉬움
>> 당도가 4.325보다 작고, 1.625보다 큰 와인 중에 알코올 도수가 11.025
>> 같거나 작은 것이 레드와인

 

▶ 당도 특성

print(dt.feature_importances_)

>> 각각 alcohol, sugar, pH 특성의 중요도

>> sugar 특성이 0.87 정도로 특성 중요도가 가장 높음

 


4. 확인문제

 

dt = DecisionTreeClassifier(min_impurity_decrease=0.0005, random_state=42)
dt.fit(train_input, train_target)

print(dt.score(train_input, train_target))
print(dt.score(test_input, test_target))

plt.figure(figsize=(20,15), dpi=300)
plot_tree(dt, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()

728x90

댓글