본문 바로가기

카테고리 없음

2024-06-12 의사결정 나무

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. 머신러닝과 딥러닝/데이터/bike.csv')
bike_df

강의 파일 데이터를 다운받아 경로를 지정해줘서 읽게 해준다.

bike_df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 33379 entries, 0 to 33378
Data columns (total 16 columns):
 #   Column        Non-Null Count  Dtype  
---  ------        --------------  -----  
 0   datetime      33379 non-null  object 
 1   count         33379 non-null  int64  
 2   holiday       33379 non-null  int64  
 3   workingday    33379 non-null  int64  
 4   temp          33379 non-null  float64
 5   feels_like    33379 non-null  float64
 6   temp_min      33379 non-null  float64
 7   temp_max      33379 non-null  float64
 8   pressure      33379 non-null  int64  
 9   humidity      33379 non-null  int64  
 10  wind_speed    33379 non-null  float64
 11  wind_deg      33379 non-null  int64  
 12  rain_1h       6771 non-null   float64
 13  snow_1h       326 non-null    float64
 14  clouds_all    33379 non-null  int64  
 15  weather_main  33379 non-null  object 
dtypes: float64(7), int64(7), object(2)
memory usage: 4.1+ MB
  • datetime: 날짜
  • count: 대여 개수
  • holiday: 휴일
  • workingday: 근무일
  • temp: 기온
  • feels_like: 체감온도m
  • 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(y=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()
datetime            0
count               0
holiday             0
workingday          0
temp                0
feels_like          0
temp_min            0
temp_max            0
pressure            0
humidity            0
wind_speed          0
wind_deg            0
rain_1h         26608
snow_1h         33053
clouds_all          0
weather_main        0
dtype: int64
bike_df = bike_df.fillna(0)
bike_df.isna().sum()
datetime        0
count           0
holiday         0
workingday      0
temp            0
feels_like      0
temp_min        0
temp_max        0
pressure        0
humidity        0
wind_speed      0
wind_deg        0
rain_1h         0
snow_1h         0
clouds_all      0
weather_main    0
dtype: int64
bike_df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 33379 entries, 0 to 33378
Data columns (total 16 columns):
 #   Column        Non-Null Count  Dtype  
---  ------        --------------  -----  
 0   datetime      33379 non-null  object 
 1   count         33379 non-null  int64  
 2   holiday       33379 non-null  int64  
 3   workingday    33379 non-null  int64  
 4   temp          33379 non-null  float64
 5   feels_like    33379 non-null  float64
 6   temp_min      33379 non-null  float64
 7   temp_max      33379 non-null  float64
 8   pressure      33379 non-null  int64  
 9   humidity      33379 non-null  int64  
 10  wind_speed    33379 non-null  float64
 11  wind_deg      33379 non-null  int64  
 12  rain_1h       33379 non-null  float64
 13  snow_1h       33379 non-null  float64
 14  clouds_all    33379 non-null  int64  
 15  weather_main  33379 non-null  object 
dtypes: float64(7), int64(7), object(2)
memory usage: 4.1+ MB
bike_df['datetime']=pd.to_datetime(bike_df['datetime'])
bike_df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 33379 entries, 0 to 33378
Data columns (total 16 columns):
 #   Column        Non-Null Count  Dtype         
---  ------        --------------  -----         
 0   datetime      33379 non-null  datetime64[ns]
 1   count         33379 non-null  int64         
 2   holiday       33379 non-null  int64         
 3   workingday    33379 non-null  int64         
 4   temp          33379 non-null  float64       
 5   feels_like    33379 non-null  float64       
 6   temp_min      33379 non-null  float64       
 7   temp_max      33379 non-null  float64       
 8   pressure      33379 non-null  int64         
 9   humidity      33379 non-null  int64         
 10  wind_speed    33379 non-null  float64       
 11  wind_deg      33379 non-null  int64         
 12  rain_1h       33379 non-null  float64       
 13  snow_1h       33379 non-null  float64       
 14  clouds_all    33379 non-null  int64         
 15  weather_main  33379 non-null  object        
dtypes: datetime64[ns](1), float64(7), int64(7), object(1)
memory usage: 4.1+ MB
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)  # Corrected 'date' to 'data'
plt.xticks(rotation=45)  # Corrected 'xtricks' to 'xticks'
plt.show()

# 2019년 월별 자전거 대여 갯수를 출력
bike_df[bike_df['year']==2019].groupby('month')['count'].mean()






month
1     193.368862
2     221.857718
3     326.564456
4     482.931694
5     438.027848
6     478.480053
7     472.745785
8     481.267366
9     500.862069
10    446.279070
11    307.295393
12    213.148886
Name: count, dtype: float64
bike_df[bike_df['year']==2020].groupby('month')['count'].mean()
month
1     260.445997
2     255.894320
3     217.135241
5     196.581064
6     290.900937
7     299.811688
8     331.528809
9     338.876478
10    293.640777
11    240.507324
12    138.993540
Name: count, dtype: float64
# covid
# 2020-04-01 이전 : precovid
# 2020-04-01 이후 ~ 2021-04-01 이전 : covid
# 2021-04-01 이후 : postcovid
# 파생변수 covid

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)
0         precovid
1         precovid
2         precovid
3         precovid
4         precovid
           ...    
33374    postcovid
33375    postcovid
33376    postcovid
33377    postcovid
33378    postcovid
Name: date, Length: 33379, dtype: object
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['season'] = bike_df['month'].apply(lambda month: 'spring' if month >= 3 and month <= 5 else 'summer' if month >= 6 and month <= 8 else 'fall' if month >= 9 and month <= 11 else 'winter')
bike_df[['month', 'season']]

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 >= 16 else 'early afternoon' if x >= 13 else 'late morning' if x >= 11 else 'early morning' if x >= 5 else 'night')
            date day_night
0     2018-01-01     night
1     2018-01-01     night
2     2018-01-01     night
3     2018-01-01     night
4     2018-01-01     night
...          ...       ...
33374 2021-08-31     night
33375 2021-08-31     night
33376 2021-08-31     night
33377 2021-08-31     night
33378 2021-08-31     night

[33379 rows x 2 columns]
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','date','hour'], axis=1, inplace=True)
bike_df.head()

bike_df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 33379 entries, 0 to 33378
Data columns (total 19 columns):
 #   Column        Non-Null Count  Dtype  
---  ------        --------------  -----  
 0   count         33379 non-null  int64  
 1   holiday       33379 non-null  int64  
 2   workingday    33379 non-null  int64  
 3   temp          33379 non-null  float64
 4   feels_like    33379 non-null  float64
 5   temp_min      33379 non-null  float64
 6   temp_max      33379 non-null  float64
 7   pressure      33379 non-null  int64  
 8   humidity      33379 non-null  int64  
 9   wind_speed    33379 non-null  float64
 10  wind_deg      33379 non-null  int64  
 11  rain_1h       33379 non-null  float64
 12  snow_1h       33379 non-null  float64
 13  clouds_all    33379 non-null  int64  
 14  weather_main  33379 non-null  object 
 15  year          33379 non-null  int32  
 16  covid         33379 non-null  object 
 17  season        33379 non-null  object 
 18  day_night     33379 non-null  object 
dtypes: float64(7), int32(1), int64(7), object(4)
memory usage: 4.7+ MB
for i in ['weather_main','covid','season','day_night']:
  print(i, bike_df[i].nunique(

  ))
weather_main 11
covid 3
season 4
day_night 1
bike_df['weather_main'].unique()
array(['Clouds', 'Clear', 'Snow', 'Mist', 'Rain', 'Fog', 'Drizzle',
       'Haze', 'Thunderstorm', 'Smoke', 'Squall'], dtype=object)
bike_df = pd.get_dummies(bike_df, columns=['weather_main','covid','season','day_night'])
bike_df.head()
pd.set_option('display.max_columns',40)
 
 

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

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

pred1 = dtr.predict(X_test)
pred1
array([  52.,  357., 1113., ...,    4.,   30.,   32.])
sns.scatterplot(x=y_test,y=pred1)

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

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

from sklearn.linear_model import LinearRegression
Ir = LinearRegression()
Ir.fit(X_train,y_train)

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

mean_squared_error(y_test,pred2,squared=False
                   )
305.2925770297244
# 의사 결정 나무 :210.74186203651976
# 선형 회귀 :221.1987722244733
210.74186203651976-221.1987722244733
-10.456910187953525
# 하이퍼 파라미터 적용
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
                   )
299.40907896411517
# 의사 결정 나무 :210.74186203651976
# 선형 회귀 :221.1987722244733
# 의사 결정 나무(하이퍼 파라미터 적용):181.29247853838177
181.29247853838177-210.74186203651976
-29.44938349813799
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(

)