트리구조로 도식화한 의사 결정 지원 도구의 일종입니다. (알고리즘이름임)
결정 트리는 3가지 종류의 노드로 구성됩니다.
이름 | 표시방법 | 이미지 |
결정 노드(decision node) | 사각형으로 보통 표시함 | |
기회 노드(chance node) | 원으로 보통 표시함 | - |
종단 노드(end node) | 삼각형으로 보통 표시함 | - |
의사 결정 나무(Decision Tree)
- 데이터를 분석하고 패턴을 파악하여 결정 규칙을 나무 구조로 나타낸 기계학습 알고리즘
- 간단하고 강력한 모델 중 하나로, 분류와 회귀 문제에 모두 사용
- 엔트로피 : 데이터의 불확실성을 측정. 특정 속성으로 데이터를 나누었을 때 엔트로피가 얼마나 감소하는지를 계산하여 정보를 얻음. 정보 익득이 높은속성을 선택하여 데이터를 나누게 됨 (= 확실하게 나누는 기준으로 사용됨)
- 지니계수 : 데이터의 불순도를 측정하는 또 다른 방법. 임의로 선택된 두 개의 요소가 서로 다른 클래스에 속할 확률을 나타냄 지니 불순도가 낮을수록 데이터가 잘 분리된 것
- 의사결정 나무는 오버피팅이 매우 잘 일어납니다
- 오버피팅(과적합): 학습데이터에서는 정확하나 테스트데이터에서는 성과가 나쁜 현상을 말함.
- 오버피팅을 방지하는 방법
- 사전 가지치기 : 나무가 다 자라기 전에 알고리즘을 멈추는 방법
- 사후 가지치기 : 나무를 끝까지 다 돌린 후에 밑에서부터 가지를 쳐 나가는 방법
bike 데이터셋
아래 데이터는 바이크가 대여된 자료을 가지고 프로젝트를 진행해보려고 합니다.
독립변수들이 들어가게되면 그 날의 바이크가 얼마나 몇 대나 대여가 될지 예측해보려고 합니다.
독립변수는 나머지들이고 종속변수는 count인 대여개수가 될것입니다.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
bike_df = pd.read_csv('/data/bike.csv')
bike_df
bike_df.info()
여기서 확인할 수 있는 것
1. 16개의 컬럼
2. 오브젝트의 유무
- 이 부분은 나중에 오브젝트에서 숫자로 변경해주어야합니다.
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)
alpha값을 준 이유는 뒤에있는 점들이 안 보일까봐 투명으로 주었습니다.
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()
이것들을 채우거나 drop시키면 되지 않습니다.
그렇다고 다 영향력이 있는 컬럼들이기때문에 null값들을 0으로 채워주도록 하겠습니다.
bike_df = bike_df.fillna(0)
bike_df.isna().sum()
bike_df.info()
여기서 이제 object를 날짜 시간(타임)을 변경해야합니다.
bike_df['datetime'] = pd.to_datetime(bike_df['datetime'])
bike_df.info()
#2018-01-01 00:00:00▶날짜, 시간 뽑기 가능
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()
2019년도에 대한 데이터를 그룹으로 바꾸고 월에 대한 카운트 세보도록 하겠습니다(평균치)
bike_df[bike_df['year'] == 2020].groupby('month')['count'].mean()
2020년도에 대한 데이터를 그룹으로 바꾸고 월에 대한 카운트 세보도록 하겠습니다(평균치)
4월데이터가 없다는걸 확인할 수 있고
4월에는 영업을 하지 않는다는것을 확인할 수 있습니다.
이상치 데이터를 확인했으니 3등분으로 임의로 나누어서 카테고리컬하게 나누었습니다.
이 부분을 함수로 만들어보겠습니다.
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)
각각 어떤 covid의 형태인지 잘 나뉘어졌습니다.
함수로 만들었지만 람다를 배웠으니 람다로도 적용해보겠습니다.
이번에는 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
# 12월~2월: winter
# 3월~5월: spring
# 6월~8월: summer
# 9월~11월: fall
|
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
맨 오른쪽 season파생변수로도 잘 들어간것을 확인할 수 있습니다.
#day_night
#21시 이후 ~ :night
#19시 이후~ : late evening
#17시 이후~ : early evening
#15시 이후~ : late afternoon
#13시 이후~ : early afternoon
#11시 이후~ : late morning
#06시 이후~ : 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
파생변수로 잘 들어가있는것을 확인할 수 있습니다.
그러면 이제 굳이 데이터라인에 들어가있지 않아도 되는 칼럼들을 drop해버리겠습니다.
bike_df.drop(['datetime', 'month', 'date', 'hour'], axis=1, inplace=True )
bike_df.head()
데이터 전처리는 어느정도 했고, 모델에 넣기 위해서 수치화되어있지않은 오브젝트가 무엇이 있는지 확인해보니
weather_main, covid, season, day_night 가 생겼습니다.
더 생긴이유는 방금 만들었기 때문입니다 이 부분도 숫자로 바꾸어줘야합니다.
일단 종류가 몇개인지 알아보도록 하겠습니다.
(유니크, 언유니크 활용)
for i in['weather_main', 'covid', 'season', 'day_night']:
print(i, bike_df[i].nunique())
이정도는 원핫인코딩으로 만들 수 있기때문에 원핫인코딩으로 하겠습니다.
그런데 웨덜메인이 좀 많으니 도대체 뭐가 있는지 확인해보려고 합니다.
bike_df['weather_main'].unique()
#array(['Clouds', 'Clear', 'Snow', 'Mist', 'Rain', 'Fog', 'Drizzle',
'Haze', 'Thunderstorm', 'Smoke', 'Squall'], dtype=object)
이렇게 11개가 있습니다.
흐린날, 맑은날, 눈오는날, 뭐 등등등 있습니다. 모두살려서 가져가겠습니다.
원핫인코딩
bike_df = pd.get_dummies(bike_df, columns=['weather_main', 'covid', 'season', 'day_night'])
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=2024)
테스트 트레이닝 값 나누기
X_train.shape , y_train.shape
#((26703, 39), (26703,))
X_test.shape , y_test.shape
#((6676, 39), (6676,))
from sklearn.tree import DecisionTreeRegressor
#DecisionTreeRegressor을 사용하는 이유는 예측하기 위해서 입니다.
dtr = DecisionTreeRegressor(random_state=2024)
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)
#210.74186203651976
210정도 오차를 확인할 수 있습니다.
사용 | 설명 |
to_datedtime() | datetime으로 변경 |
.apply | 함수 처리되는 매소드 |
'데이터 분석 및 시각화' 카테고리의 다른 글
[ML] 서포트 벡터 머신(SVM),스케일링을 통한 손글씨 데이터셋만들어보기 (1) | 2024.07.08 |
---|---|
[ML] 의사 결정 나무(decision tree)_bike 데이터 활용(2) (0) | 2024.07.06 |
[ML] 사이킷런(Scikit-learn) (0) | 2024.06.30 |
[데이터 시각화] 떡볶이 프렌차이즈의 입점전략은 바로 이것. (0) | 2024.06.29 |
[ML] 머신러닝(Machine Learning) (0) | 2024.06.28 |