인공지능/데이터분석

서울 자전거 공유 수요 예측 데이터셋

Ryuzy 2025. 1. 8. 02:05
728x90
반응형

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)
728x90
반응형

'인공지능 > 데이터분석' 카테고리의 다른 글

슈퍼스토어 마케팅 캠페인 데이터셋  (0) 2025.01.10
호텔 예약 수요 데이터셋  (0) 2025.01.09
주택 임대료 예측 데이터셋  (2) 2025.01.03
사이킷런  (0) 2024.12.31
머신러닝과 딥러닝  (3) 2024.12.23