머신러닝 기초 | 로지스틱 회귀로 와인 분류 | 결정트리 / 가지치기 | 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

    댓글