1. 서울 자전거 공유 수요 데이터셋
서울시의 공공자전거 대여 서비스인 ‘따릉이’의 대여 수요를 예측하는 문제에 사용되는 데이터셋입니다. 특정 시간대와 날씨, 요일, 공휴일 여부, 기온, 습도 등 다양한 데이터를 활용하여 자전거 대여 수요를 예측합니다.
2. 데이터셋 컬럼
- Date : 연월일
- Rented Bike count - 매 시간마다 대여한 자전거 수
- Hour - 하루 중 시간
- Temperature - 온도
- Humidity - 습도 %
- Windspeed - 풍속 m/s
- Visibility - 가시거리 m
- Dew point temperature - 이슬점 온도
- Solar radiation - 태양 복사 MJ/m2
- Rainfall - 강우량 mm
- Snowfall - 적설량 cm
- Seasons - 겨울, 봄, 여름, 가을
- Holiday - 휴일/휴일 없음
- Functional Day - 운영되지 않았던 날, 정상적으로 운영된 날
3. 데이터 전처리 및 탐색적 데이터 분석 (EDA)
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
bike_df = pd.read_csv('/본인의 구글드라이브 경로/SeoulBikeData.csv', encoding='CP949')
bike_df
※ CP949
- Microsoft Windows의 한국어 문자 인코딩입니다.
- EUC-KR을 확장한 형태로, 더 많은 한국어 문자(한자, 확장 문자 등)를 지원합니다.
- 주로 Windows 환경에서 저장된 한글 파일에서 사용됩니다.
bike_df.info()
bike_df.describe()
bike_df.columns
bike_df.columns = ['Date', 'Rented Bike Count', 'Hour', 'Temperature', 'Humidity',
'Wind speed', 'Visibility', 'Dew point temperature',
'Solar Radiation', 'Rainfall', 'Snowfall', 'Seasons',
'Holiday', 'Functioning Day']
bike_df.head()
sns.scatterplot(x='Temperature', y='Rented Bike Count', data=bike_df, alpha=0.3)
sns.scatterplot(x='Wind speed', y='Rented Bike Count', data=bike_df, alpha=0.3)
sns.scatterplot(x='Visibility', y='Rented Bike Count', data=bike_df, alpha=0.3)
sns.scatterplot(x='Hour', y='Rented Bike Count', data=bike_df, alpha=0.3)
bike_df.isna().sum()
bike_df.info()
bike_df['Date'] = pd.to_datetime(bike_df['Date'], format='%d/%m/%Y')
bike_df.info()
bike_df['year'] = bike_df['Date'].dt.year
bike_df['month'] = bike_df['Date'].dt.month
bike_df['day'] = bike_df['Date'].dt.day
bike_df.head()
plt.figure(figsize=(14, 4))
sns.lineplot(x='Date', y='Rented Bike Count', data=bike_df)
plt.xticks(rotation=45)
plt.show()
bike_df[bike_df['year'] == 2017].groupby('month')['Rented Bike Count'].mean()
bike_df[bike_df['year'] == 2018].groupby('month')['Rented Bike Count'].mean()
bike_df['TimeOfDay'] = pd.cut(bike_df['Hour'],
bins=[0, 5, 11, 17, 23],
labels=['Dawn', 'Morning', 'Afternoon', 'Evening'],
include_lowest=True)
※ pd.cut()
pd.cut()은 숫자 데이터를 구간(bins)으로 나누어 범주형 데이터로 변환하는 데 사용됩니다. 주로 연속형 데이터를 특정 범주로 분류할 때 활용됩니다.
- bins: 숫자 데이터를 나눌 경계값(구간)입니다.
0 ≤ Hour ≤ 5 | Dawn (새벽) |
5 < Hour ≤ 11 | Morning (아침) |
11 < Hour ≤ 17 | Afternoon (오후) |
17 < Hour ≤ 23 | Evening (저녁) |
- 주의: bins의 경계값은 오른쪽 경계값(])을 포함합니다.
bike_df.head()
sns.barplot(x='Functioning Day', y='Rented Bike Count', data=bike_df)
※ barplot의 bar의 역할
- 신뢰구간(CI): 평균값이 속할 것으로 예상되는 값의 범위입니다.
- 바 그래프에서 신뢰구간: 검은색 심지(Error Bar)로 나타납니다.
- 신뢰구간이 좁다: 평균값에 대한 확신이 높다.
- 신뢰구간이 넓다: 평균값에 대한 확신이 낮고 데이터가 흩어져 있다.
bike_df['Functioning Day'].value_counts()
bike_df[bike_df['Functioning Day'] == 'Yes']
bike_df[bike_df['Functioning Day'] == 'No']
bike_df.info()
bike_df = bike_df.drop('Date', axis=1)
bike_df.head()
bike_df.select_dtypes(exclude=['number']).columns.tolist()
for i in bike_df.select_dtypes(exclude=['number']).columns.tolist():
print(i, bike_df[i].nunique())
bike_df = pd.get_dummies(bike_df, columns=bike_df.select_dtypes(exclude=['number']).columns.tolist(), drop_first=True)
bike_df.head()
# 모든 컬럼 간 상관관계 분석
correlation_matrix = bike_df.corr()
# 목표 변수와의 상관관계만 확인
target_corr = correlation_matrix['Rented Bike Count'].sort_values(ascending=False)
print(target_corr)
※ corr() 함수
corr() 함수는 데이터프레임의 숫자형 열 간의 상관관계를 계산하는 데 사용됩니다. 상관관계는 두 변수 간의 선형 관계를 나타내며, 주로 -1에서 1 사이의 값으로 표현됩니다.
- corr()는 Pearson 상관계수를 기본으로 사용합니다.
- 숫자형 열만 상관관계 분석에 포함됩니다.
- 높은 상관관계(>|0.5|): 강한 관계
- 낮은 상관관계(<|0.2|): 약한 관계
corr()를 사용하여 높은 상관관계를 가진 컬럼을 식별하고 제거할지 여부를 판단할 수 있습니다. 특히, 다중공선성(multicollinearity) 문제가 발생할 경우 머신러닝 모델의 성능이 저하될 수 있으므로, 상관관계가 높은 컬럼을 적절히 제거하는 것이 중요합니다.
※ 다중공선성
다중공선성(Multicollinearity)은 회귀 분석에서 독립 변수들(설명 변수) 간에 강한 상관관계가 존재하는 현상을 의미합니다. 이러한 상관관계가 높으면 각 독립 변수가 종속 변수에 미치는 개별적인 영향을 정확하게 추정하기 어려워지며, 회귀 계수의 추정치가 불안정해져 작은 데이터 변화에도 크게 변할 수 있습니다. 이는 모델의 예측 성능 저하와 해석의 신뢰성 감소로 이어질 수 있으므로, 다중공선성이 높은 변수를 식별하고 제거하거나 조정하는 것이 중요합니다.
plt.figure(figsize=(16, 12))
sns.heatmap(correlation_matrix, annot=True, fmt='.2f', cmap='coolwarm')
plt.title('Feature Correlation Heatmap')
plt.show()
bike_df = bike_df.drop(['Dew point temperature'], axis=1)
bike_df.head()
bike_df.info()
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(bike_df.drop('Rented Bike Count', axis=1), bike_df['Rented Bike Count'], test_size=0.3, random_state=2025)
X_train.shape, y_train.shape
X_test.shape, y_test.shape
4. 결정 트리
결정 트리(Decision Tree)는 데이터를 기반으로 의사결정을 수행하는 트리 구조의 예측 모델입니다. 루트 노드(root node)에서 시작해 각 노드는 특정 특성(feature)의 조건에 따라 가지(branch)로 분기되며, 최종적으로 리프 노드(leaf node)에 도달해 예측 결과(클래스나 값)를 도출합니다. 주로 분류(Classification)와 회귀(Regression) 문제에 사용되며, 데이터의 패턴을 직관적으로 시각화할 수 있어 해석이 용이합니다. 하지만 트리가 너무 깊어지면 과적합(overfitting) 문제가 발생할 수 있으므로 가지치기(pruning)나 최대 깊이 설정 등으로 제어해야 합니다.
- 전체 데이터셋을 하나의 노드로 시작합니다.
- 최적의 특성(feature)과 분할 기준(threshold)을 찾아 첫 번째 분할을 수행합니다.
- 분류 (Classification):
- Gini 불순도(Gini Impurity)
- 엔트로피(Entropy)
- 회귀 (Regression):
- 평균 제곱 오차(Mean Squared Error, MSE)
- 절대 평균 오차(Mean Absolute Error, MAE)
- 각 하위 노드에 대해 위 단계를 반복합니다.
- 이 과정을 통해 트리는 여러 깊이로 성장합니다.
- 모든 노드가 더 이상 나눌 수 없거나 특정 조건(max_depth, min_samples_split)을 만족할 때까지 반복됩니다.
- 더 이상 분할이 불가능할 때 리프 노드가 생성됩니다.
- 분류 문제: 가장 많은 클래스가 있는 클래스를 예측값으로 사용
- 회귀 문제: 평균값을 예측값으로 사용
※ Gini 불순도 (Gini Impurity)
- Gini 불순도는 한 노드에 있는 데이터의 순수도(Purity)를 측정하는 지표입니다.
- 한 노드에 있는 샘플들이 동일한 클래스에 속할 확률이 높을수록 Gini 불순도는 낮아집니다.
- 즉, 노드가 "얼마나 섞여 있는지"를 나타냅니다.
※ 엔트로피 (Entropy)
- 엔트로피는 정보의 불확실성(혼란도, Uncertainty)을 측정합니다.
- 엔트로피가 높을수록 해당 노드에 있는 데이터는 더 섞여 있으며, 예측하기 어렵습니다.
- 엔트로피는 데이터가 균등하게 분포될 때 최대값을 가집니다.
from sklearn.tree import DecisionTreeRegressor
dtr = DecisionTreeRegressor(random_state=2025)
dtr.fit(X_train, y_train)
pred1 = dtr.predict(X_test)
sns.scatterplot(x=y_test, y=pred1)
※ DecisionTreeRegressor
DecisionTreeRegressor는 주어진 데이터를 반복적으로 분할하여 예측을 수행합니다. 각 분할은 데이터의 목표 변수 값을 예측하는 데 가장 적합한 값을 찾기 위해 이루어집니다. 이를 통해 데이터를 점차 더 작은 부분으로 나누고, 각 부분에서 평균값을 예측값으로 사용하는 방식입니다. DecisionTreeRegressor 데이터를 두 가지 그룹으로 분할합니다. 각 분할에서 목표는 두 그룹의 MSE가 가능한 한 낮도록 만드는 것입니다. 즉, 각 분할에서의 MSE가 최소화되도록 분할점을 찾습니다.
from sklearn.metrics import root_mean_squared_error
root_mean_squared_error(y_test, pred1)
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)
root_mean_squared_error(y_test, pred2)
# 하이퍼 파라미터 적용
dtr = DecisionTreeRegressor(random_state=2025, max_depth=50, min_samples_leaf=30)
dtr.fit(X_train, y_train)
pred3 = dtr.predict(X_test)
root_mean_squared_error(y_test, pred3)
from sklearn.tree import plot_tree
plt.figure(figsize=(24, 12))
plot_tree(dtr, max_depth=5, fontsize=10, feature_names=X_train.columns)
plt.show()
from sklearn.ensemble import RandomForestRegressor
rf = RandomForestRegressor(random_state=2025)
rf.fit(X_train, y_train)
pred4 = rf.predict(X_test)
root_mean_squared_error(y_test, pred4)
rf.feature_importances_
feature_imp = pd.DataFrame({
'features': X_train.columns,
'importances': rf.feature_importances_
})
feature_imp
top10 = feature_imp.sort_values('importances', ascending=False).head(10)
top10
plt.figure(figsize=(5, 10))
sns.barplot(x='importances', y='features', data=top10)
'인공지능 > 데이터분석' 카테고리의 다른 글
슈퍼스토어 마케팅 캠페인 데이터셋 (0) | 2025.01.10 |
---|---|
호텔 예약 수요 데이터셋 (0) | 2025.01.09 |
주택 임대료 예측 데이터셋 (2) | 2025.01.03 |
사이킷런 (0) | 2024.12.31 |
머신러닝과 딥러닝 (3) | 2024.12.23 |