ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [혼공머] 5-1. 결정 트리
    Data Science/딥러닝 & 머신러닝 2025. 1. 12. 19:31

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

    1. 배경

    • 알코올, 도수, 당소, pH 값에 로지스틱 회귀 모델을 적용 → 레드 와인과 화이트 와인 구분

    2. 데이터셋 준비

    • head() : 앞 6개 데이터 확인
    • info() : 각 열의 데이터 타입과 누락 여부
    • describe() : 열에 대한 간략한 통계 출력
    import pandas as pd
    wine = pd.read_csv('<https://bit.ly/wine_csv_data>')
    wine.head()
    wine.info()
    wine.describe()
    

    0 이면 레드 와인

    1이면 화이트 와인 (양성)

    6497개의 샘플

    4개의 열은 실숫값

    누락 없음

    스케일 달라서 표준화 필요

    3. 훈련 데이터와 타겟 데이터 분리

    data = wine[['alcohol', 'sugar', 'pH']].to_numpy()
    target = wine['class'].to_numpy()
    
    # 훈련 세트와 테스트 세트로 분리
    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)
    print(train_input.shape, test_input.shape) # (5197, 3) (1300, 3)
    

    4. 데이터 전처리 - 표준화

    from sklearn.preprocessing import StandardScaler
    ss = StandardScaler()
    ss.fit(train_input)
    train_scaled = ss.transform(train_input)
    test_scaled = ss.transform(test_input)
    

    5. 로지스틱 회귀 모델 훈련

    from sklearn.linear_model import LogisticRegression
    lr = LogisticRegression()
    lr.fit(train_input, train_target)
    print(lr.score(train_scaled, train_target)) # 0.78
    print(lr.score(test_scaled, test_target)) # 0.77
    
    • 정확도 둘 다 낮아서 과소적합
    • 규제 매개변수를 바꾸거나 다항 특성 추가

    6. 로지스틱 회귀 모델의 문제

    • 로지스틱 회귀가 학습한 계수와 절편
      • 왜 해당 계수를 학습했는지 잘은 모름
      • 정확한 숫자의 의미는 모름
      • 다항 특성 추가 시 설명하기 어려움

    2. 결정 트리

    1. 결정 트리

    • 질문을 추가하며 분류 정확도를 높이는 알고리즘
    • 구성 요소
      • 노드 : 훈련 데이터의 특성에 대한 표현
        • 루트 노드 : 맨 위의 노드
        • 리프 노드 : 맨 아래에 달린 노드
      • 가지 : 테스트의 결과
    • sklearn.tree의 알고리즘 사용
      • DeceisionTreeClassifier : 사이킷런의 결정 트리 알고리즘
        • random_state는 실습 때문에 지정한 것.
        • criterion : 데이터를 분할할 기준
      • plot_tree : 트리 그림 확인
        • max_depth 매개 변수 : 깊이 제한
        • filled 매개변수 : 클래스에 맞게 노드 색칠
        • features_names 매개변수 : 특성의 이름 전달

    2. 결정 트리 모델 훈련

    from sklearn.tree import DecisionTreeClassifier
    dt = DecisionTreeClassifier(random_state=42) 
    dt.fit(train_scaled, train_target)
    print(dt.score(train_scaled, train_target)) # 0.99
    print(dt.score(test_scaled, test_target)) # 0.85
    

     

    from sklearn.tree import plot_tree 
    plt.figure(figsize=(10,7)) 
    plot_tree(dt) plt.show()
    
    plt.figure(figsize=(10, 7)) 
    plot_tree(dt, max_depth=1, filled=True, feature_names=['alcohol', 'sugar', 'pH']) plt.show()

    3. 트리 분석하기

    • 노드의 구성 요소
      • 테스트 조건
      • 불순도
      • 총 샘플 수
      • 클래스별 샘플 수
    • 화살표 : 조건 만족하면 Yes (왼쪽)
    • 루트 노드의 색 변화 - filled=True
      • 클래스의 비율이 높아질수록 점점 진한 색
    • 결정 트리에서의 예측 : 리프 노드에서 가장 많은 클래스가 예측 클래스
        •  

    3. 불순도

    1. 지니 불순도

    • DecisionTreeClassifier 클래스의 criterion 매개변수의 기본값
    • 지니 불순도 공식
      • 지니 불순도 = 1 - (음성 클래스 비율^2 + 양성 클래스 비율^2) 
    • 작을수록 순수하다.
    • 부모 노드와 자식 노드의 불순도 차이가 크도록 트리를 성장시킨다.

    2. 정보 이득 : 불순도의 차이; 클수록 좋다.

    부모의 불순도 - (왼쪽 노드 샘플 수 / 부모의 샘플 수)왼쪽 노드 불순도 - (오른쪽 노드 샘플 수 / 부모의 샘플 수)오른쪽 노드 불순도

     

    3. 엔트로피 불순도

    • criterion =’entropy’
    • 제곱을 사용하는 지니 불순도 대신 밑이 2인 ‘로그’ 사용
      • -음성 클래스 비율 log_2(음성 클래스 비율) - 양성 클래스 비율log_2(양성 클래스 비율) 

    → 불순도 기준을 사용해 정보 이득이 최대가 되도록 노드를 분할

    → 노드를 순수하게 나눌수록 정보 이득이 커진다.

    → 노드를 순수하게 나눌수록 정보 이득이 커진다.


    4. 가지치기

    1. 배경

    • 트리가 제한 없이 자라나면 훈련 세트보다 테스트 세트에서 점수가 크게 낮았다.
    • 무작정 자라나면 일반화가 잘 안 된다.

    2. 가지치기 방법

    • 트리의 최대 깊이 지정
      • DecisionTreeClassifier 클래스의 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))
      # (0.8454877814123533, 0.8415384615384616)
      
      훈련 세트의 성능은 감소했지만 테스트 세트의 성능은 거의 유지
      • 트리 구조 확인
      • 0 : 레드와인, 1 : 화이트 와인
    • 당도가 ‘음수’가 될 수는 없다.
      • 불순도는 클래스 별 비율로 계산하니까 특성값에 표준화를 할 필요가 없다.
      • 결정 트리의 장점 : 특성값에 표준화를 할 필요가 없는 것
    • 위의 사진에서는 당도가 음수라는 특이한 점이 있다.

    3. 표준화가 필요 없는 결정트리

    dt = DecisionTreeClassifier(max_depth=3, random_state=42)
    dt.fit(train_input, train_target)
    dt.score(train_input, train_target), dt.score(test_input, test_target)
    # (0.8454877814123533, 0.8415384615384616)
    
    plt.figure(figsize=(20, 15))
    plot_tree(dt, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
    plt.show()
    

    4. 트리의 특성 중요도

    dt.feature_importances_

    5. 이해하기 쉬운 결정 트리 모델 전체 소스 코드

    # 데이터 준비
    import pandas as pd
    wine = pd.read_csv('<https://bit.ly/wine_csv_data>')
    wine.head()
    wine.info()
    
    # 훈련 데이터와 타겟 데이터 준비
    data = wine[['alcohol', 'sugar', 'pH']].to_numpy()
    target = wine['class'].to_numpy()
    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)
    
    # 로지스틱 회귀의 과정
    from sklearn.preprocessing import StandardScaler
    ss = StandardScaler()
    ss.fit(train_input)
    train_scaled = ss.transform(train_input)
    test_scaled = ss.transform(test_input)
    
    from sklearn.linear_model import LogisticRegression
    lr = LogisticRegression()
    lr.fit(train_scaled, train_target)
    lr.score(train_scaled, train_target), lr.score(test_scaled, test_target)
    
    # 결정 트리
    from sklearn.tree import DecisionTreeClassifier
    dt = DecisionTreeClassifier(random_state=42)
    dt.fit(train_input, train_target)
    dt.score(train_input, train_target), dt.score(test_input, test_target)
    
    # 전체적인 결정 트리 확인
    import matplotlib.pyplot as plt
    from sklearn.tree import plot_tree 
    plt.figure(figsize=(10, 7)) 
    plot_tree(dt)
    plt.show()
    
    # 결정 트리 시각화
    plt.figure(figsize=(10, 7))
    plot_tree(dt, max_depth=1, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
    plt.show()
    
    # 불순도
    DecisionTreeClassifier(criterion='gini')
    DecisionTreeClassifier(criterion='entropy')
    
    # 가지치기
    dt = DecisionTreeClassifier(max_depth=3, random_state=42)
    dt.fit(train_input, train_target)
    dt.score(train_input, train_target), dt.score(test_input, test_target)
    plt.figure(figsize=(20, 15))
    plot_tree(dt, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
    plt.show()
    
    # 특성 중요도
    dt.feature_importances_
    
    
Designed by Tistory.