본문 바로가기
머신러닝 & 딥러닝

6. 의사 결정 나무

by 곽정우 2024. 6. 11.

1. bike 데이터셋

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
bike_df = pd.read_csv('/content/drive/MyDrive/KDT/6.머신러닝과 딥러닝/Data/bike.csv')
bike_df

bike.csv
2.42MB

bike_df.info()

datetime: 날짜
count: 대여 개수
holiday: 휴일
workingday: 근무일
temp: 기온
feels_like: 체감온도
temp_min: 최저온도
temp_max: 최고온도
pressure: 기압
humidity: 습도
wind_speed: 풍속
wind_deg: 풍향
rain_1h: 1시간당 내리는 비의 양
snow_1h: 1시간당 내리는 눈의 양
clouds_all: 구름의 양
weather_main: 날씨
bike_df.describe()

sns.displot(bike_df['count'])

sns.boxplot(bike_df['count'])

sns.scatterplot(x='feels_like', y='count', data=bike_df, alpha=0.3)

sns.scatterplot(x='pressure', y='count', data=bike_df, alpha=0.3)

sns.scatterplot(x='wind_speed', y='count', data=bike_df, alpha=0.3)

sns.scatterplot(x='wind_deg', y='count', data=bike_df, alpha=0.3)

bike_df.isna().sum()

bike_df = bike_df.fillna(0)
bike_df.isna().mean()

bike_df.info()

bike_df['datetime'] = pd.to_datetime(bike_df['datetime'])
bike_df.info()

bike_df

# year, month, hour 파생변수 만들기

bike_df['year'] = bike_df['datetime'].dt.year
bike_df['month'] = bike_df['datetime'].dt.month
bike_df['hour'] = bike_df['datetime'].dt.hour
bike_df.head()

bike_df['date'] = bike_df['datetime'].dt.date
bike_df.head()

plt.figure(figsize=(14, 4))
sns.lineplot(x='date', y='count', data=bike_df)
plt.xticks(rotation=45)
plt.show()

bike_df[bike_df['year'] == 2019].groupby('month')['count'].mean()

# 2020년 월별 자전거 대여 갯수를 출력

bike_df[bike_df['year'] == 2020].groupby('month')['count'].mean() # 2020년 4월 데이터가 없음

# covid
# 2020-04-01 이전: precovid
# 2021-04-01 이전: covid
# 이후: postcovid

def covid(date):
    if str(date) < '2020-04-01':
        return 'precovid'
    elif str(date) < '2021-04-01':
        return 'covid'
    else:
        return 'postcovid'
bike_df['date'].apply(covid)

bike_df['covid'] = bike_df['date'].apply(lambda date: 'precovid' if str(date) < '2020-04-01' else 'covid' if str(date) < '2021-04-01' else 'postcovid')
bike_df

# season
# 3월 ~ 5월: spring
# 6월 ~ 8월: summer
# 9월 ~ 11월: fall
# 12월 ~ 2월: winter

bike_df['season'] = bike_df['month'].apply(lambda x: 'winter' if x == 12 
                                           else 'fall' if x >= 9 
                                           else 'summer' if x >= 6 
                                           else 'spring' if x >= 3 
                                           else 'winter')
bike_df[['month', 'season']]

# day_night 
# 21시 이후: night
# 19시 이후: late evening 
# 17시 이후: early evening 
# 15시 이후: late afternoon
# 13시 이후: early afternoon 
# 11시 이후: late morning 
# 6시 이후: early morning

bike_df['day_night'] = bike_df['hour'].apply(lambda x: 'night' if x >= 21 
                                             else 'late evening' if x >= 19 
                                             else 'early evening' if x >= 17 
                                             else 'late afternoon' if x >= 15 
                                             else 'early afternoon' if x >= 13 
                                             else 'late morning' if x >= 11 
                                             else 'early morning' if x >= 6
                                             else 'night')
bike_df.head()

bike_df.drop(['datetime', 'month', 'hour', 'date'], axis=1, inplace=True)
bike_df.head()

bike_df.info()

for i in ['weather_main', 'covid', 'season', 'day_night']:
    print(i, bike_df[i].nunique())

bike_df['weather_main'].unique()

bike_df = pd.get_dummies(bike_df, columns=['weather_main', 'covid', 'season', 'day_night'])
bike_df.head()

pd.set_option('display.max_columns', 40)
bike_df.head()

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(bike_df.drop('count', axis=1), bike_df['count'], test_size=0.2, random_state=10)
X_train.shape,  y_train.shape

X_test.shape,y_test.shape

 

2. 의사 결정 나무(Decision Tree)

  • 데이터를 분석하고 패턴을 파악하여 결정 규칙을 나무 구조로 나타낸 기계학습 알고리즘
  • 간단하고 강력한 모델 중 하나로, 분류와 회귀 문제에 모두 사용
  • 지니계수(지니 불순도, Gini Impurity): 분류 문제에서 특정 노드의 불순도를 나타내는데, 노드가 포함하는 클래스들이 혼잡되어 있는 정도를 나타냄
    • 0에서 1까지의 값을 가지며, 0에 가까울수록 노드의 값이 불순도가 없음을 의미
    • 로그 연산이 없어 계산이 상대적으로 빠름
  • 엔트로피: 어떤 집합이나 데이터의 불확실성, 혼잡도를 나타내는데, 노드의 불순도를 측정하는데 활용
    • 00에서 무한대까지의 값을 가지며, 0에 가까울수록 노드의 값이 불순도가 없음을 의미
    • 로그 연산이 포함되어 있어 계산이 복잡
  • 오버피팅 (과적합): 학습데이터에서는 정확하나 테스트데이터에서는 성과가 나쁜 현상을 말함. 의사 결정 나무는 오버피티이 매우 잘 일어남
    • 오버피팅을 방지하는 방법
      • 사전 가지치기: 나무가 다 자라기 전에 알고리즘을 멈추는 방법
      • 사후 가지치기: 나무를 끝까지 다 돌린 후 밑에서부터 가지를 쳐나가는 방법
from sklearn.tree import DecisionTreeRegressor
# 하이퍼 파라미터: 모델에 옵션을 주는 파라미터
# random_state: 랜덤한 값을 유지

dtr = DecisionTreeRegressor(random_state=2024)
dtr.fit(X_train, y_train)

pred1 = dtr.predict(X_test)
sns.scatterplot(x=y_test, y=pred1)

from sklearn.metrics import mean_squared_error
mean_squared_error(y_test, pred1, squared=False)

 

3. 선형회귀 vs 의사결정나무

# 선형회귀

from sklearn.linear_model import LinearRegression
# 선형회귀 객체 생성

lr = LinearRegression()
# 학습

lr.fit(X_train, y_train)

# 테스트 데이터로 예측

pred2 = lr.predict(X_test)
sns.scatterplot(x=y_test, y=pred2)

mean_squared_error(y_test, pred2, squared=False)

# 의사 결정 나무: 223.41421468685962
# 선형 회귀: 219.59749939160645
223.41421468685962 - 219.59749939160645

# 하이퍼 파라미터 적용
# max_depth: 트리의 최대 깊이를 제한
# min_samples_leaf: 데이터가 나뉘어 최소 30개로 분류되었을때 가지치기를 끝냄

dtr = DecisionTreeRegressor(random_state=2024, max_depth=50, min_samples_leaf=30)
dtr.fit(X_train, y_train)

pred3 = dtr.predict(X_test)
mean_squared_error(y_test, pred3, squared=False)

# 의사 결정 나무: 223.41421468685962
# 선형 회귀: 219.59749939160645
# 의사 결정 나무 (하이퍼 파라미터 적용): 181.1548212906948
181.1548212906948 - 223.41421468685962

from sklearn.tree import plot_tree
plt.figure(figsize=(24, 12))
plot_tree(dtr, max_depth=5, fontsize=10)
plt.show() # 의사결정나무 그래프

plt.figure(figsize=(24, 12))
plot_tree(dtr, max_depth=5, fontsize=10, feature_names=X_train.columns)
plt.show() # 하이퍼파라미터로 피쳐의 이름이 나오도록 표시하기

'머신러닝 & 딥러닝' 카테고리의 다른 글

8. 서포트 벡터 머신  (0) 2024.06.12
7. 로지스틱 회귀  (0) 2024.06.12
5. 선형 회귀  (0) 2024.06.11
4. 타이타닉 데이터셋  (0) 2024.06.10
3. 아이리스 데이터셋  (0) 2024.06.10