머신러닝

[ 머신러닝 ] 의사결정나무

예진또이(애덤스미스 아님) 2023. 9. 6. 03:06
728x90

🌀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/머신러닝 딥러닝/bike.csv')

bike_df

✔️ 결과

bike_df.info()

✔️ 결과

  • datetime: 날짜
  • count: 대여갯수
  • holiday: 휴일
  • workingday: 근무일
  • temp: 기온
  • feels_like: 체감온도
  • temp_min: 최저온도
  • temp_max: 최고온도
  • pressure: 기압
  • humidity: 습도
  • wind_speed: 풍속
  • wind_deg: 풍향
  • rain_1h: 강우량
  • snow_1h: 강설량
  • 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()
 

✔️ 결과

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.isna().mean()

✔️ 결과

datetime        0.000000
count           0.000000
holiday         0.000000
workingday      0.000000
temp            0.000000
feels_like      0.000000
temp_min        0.000000
temp_max        0.000000
pressure        0.000000
humidity        0.000000
wind_speed      0.000000
wind_deg        0.000000
rain_1h         0.797148
snow_1h         0.990233
clouds_all      0.000000
weather_main    0.000000
dtype: float64
 
bike_df = bike_df.fillna(0)
bike_df.isna().mean()

 

✔️ 결과
datetime        0.0
count           0.0
holiday         0.0
workingday      0.0
temp            0.0
feels_like      0.0
temp_min        0.0
temp_max        0.0
pressure        0.0
humidity        0.0
wind_speed      0.0
wind_deg        0.0
rain_1h         0.0
snow_1h         0.0
clouds_all      0.0
weather_main    0.0
dtype: float64
 
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.head()
 
✔️ 결과
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()
✔️ 결과
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()
# 2020년 4월 데이터가 없음을 알 수 있다
 

✔️ 결과

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
# 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'

 

 
 
covid(bike_df['date'])   # 시리즈를 넣게 되면 하나만 비교가 되기 때문에 결과적으로는 쓸모없다ㅜ
--------------------------------------------------------------------------------------------
#결과
precovid
 
 
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.head()

✔️ 결과

 

 

# 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']]
 
✔️ 결과
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')
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  int64  
 16  covid         33379 non-null  object 
 17  season        33379 non-null  object 
 18  day_night     33379 non-null  object 
dtypes: float64(7), int64(8), object(4)
memory usage: 4.8+ 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 7

 

 
 
bike_df['weather_main'].unique()
✔️ 결과
array(['Clouds', 'Clear', 'Snow', 'Mist', 'Rain', 'Fog', 'Drizzle',
       'Haze', 'Thunderstorm', 'Smoke', 'Squall'], dtype=object)
plt.figure(figsize=(10, 5))
sns.boxplot(x='weather_main', y='count', data=bike_df)

 

✔️ 결과
 
 
bike_df = pd.get_dummies(bike_df, columns =['weather_main', 'covid', 'season', 'day_night'])
bike_df.head()
✔️결과
 
pd.set_option('display.max_columns', 45)
 
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)
 

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

  • 데이터를 분석하여 그 사이에 존재하는 패턴을 예측 가능한 규칙들의 조합으로 나타내며, 그 모양이 '나무'와 같다고 해서 의사 결정 나무라고 부름
  • 분류(Classification)과 회귀(Regression)모두 가능
  • 지니계수(Gini Index): 0에 가까울수록 클래스에 속한 불순도가 낮음
  • 엔트로피(Entropy): 결정을 내릴만한 충분한 정보가 데이터에 없다고 보는것. (0에 가까울 수록 결정을 내릴만한 충분한 정보가 있다)
  • 오버피팅(과적합): 훈련데이터에서는 정확하나 테스트데이터에서는 성과가 나쁜 현상을 말한. 훈련데이터가 적거나 노이즈가 있을 떄 또는 알고리즘 자체가 나쁠 때 발생. 의사결정 나무에서는 나무의 가지가 너무 많거나 크기가 클 때 발생
    • 의사결정 나무에서 오버피팅을 피하는 방법
      • 사전 가지치기: 나무가 다 자라기 전에 알고리즘을 멈추는 방법
      • 사후 가지치기: 의사결정 나무를 끝까지 돌린 후 밑에서부터 가지를 쳐 나가는 방법
 
 from sklearn.tree import DecisionTreeRegressor
 
dt = DecisionTreeRegressor(random_state=10)
dt.fit(X_train, y_train)

 

✔️ 결과
 
pred1= dt.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)
✔️ 결과
228.42843328100884

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)
 

✔️ 결과

228.26128192004947
 
 
 
# 하이퍼 파라미터 적용 
df = DecisionTreeRegressor(random_state=10, max_depth=50, min_samples_leaf=30)
 
dt.fit(X_train, y_train)
 
✔️ 결과
pred3 = dt.predict(X_test)
 
mean_squared_error(y_test, pred3, squared=False)
 

✔️ 결과

228.42843328100884
 
# 의사 결정 나무 RMSE:  228.42843328100884
# 선형 회귀 RMSE:  228.26128192004947
# 의사 결정 나무 파라미터 튜닝 RMSE: 
from sklearn.tree import plot_tree
 
plt.figure(figsize=(24, 12))
plot_tree(dt, max_depth=5, fontsize=12)
plt.show()
 
 

✔️ 결과

728x90
반응형