| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |
- 힙정렬
- 머신러닝
- Transformer
- dementional reduction
- 자연어처리
- 데이터엔지니어
- 소프트웨어 개발
- LangGraph
- 트랜스포머
- RDBMS
- python기초
- UMAP
- RNN
- TTS
- Python
- 생성형 인공지능
- SQL
- 정보처리기사
- 알고리즘
- 랭그래프
- 객체지향
- 기초
- 딥러닝
- CNN
- python 기초
- 데이터 시각화
- CLIP
- 캐글
- ASR
- 에이전트
- Today
- Total
수달이네 기술 블로그
15. 서울 따릉이 수요 예측2 본문
컬럼간 상관관계 분석(다중공선성 확인)
위의 전처리로 인해 object컬럼은 사라졌다. 이제 컬럼간의 상관관계를 확인하거나, 학습해보자
correlation_matrix = bike_df.corr()
bike_df
판다스에서 제공하는 correlation_matrix를 살펴보자면]
Rented Bike CountHourTemperatureHumidityWind speedVisibilityDew point temperature
| Rented Bike Count | Hour | Temperature | Humidity | |
| Rented Bike Count | 1.000000 | 4.102573e-01 | 0.538558 | -0.199780 |
| Hour | 0.410257 | 1.000000e+00 | 0.124114 | -0.241644 |
| Temperature | 0.538558 | 1.241145e-01 | 1.000000 | 0.159371 |
| Humidity | -0.199780 | -2.416438e-01 | 0.159371 | 1.000000 |
컬럼간의 상관관계를 소수점으로 나타내 보여준다(피어슨 상관계수)
- 1.0은 관계가 있는 것이 아닌 아예 같은 컬럼
- 0.5 이상: 양의 상관관계가 존재
- -0.5이하: 음의 상관관계가 존재
- 0에 가까움 : 상관관계 없음
우리가 알아야할 타깃값인 Rented Bike Count와의 상관관계를 확인하여 정렬하면
target_corr = correlation_matrix['Rented Bike Count'].sort_values(ascending=False)
target_corr
# Rented Bike Count 1.000000
# Temperature 0.538558
# Hour 0.410257
# Dew point temperature 0.379788
# TimeOfDay_Evening 0.322978
# Seasons_Summer 0.296549
# Solar Radiation 0.261837
# year 0.215162
# Functioning Day_Yes 0.203943
# Visibility 0.199280
# month 0.133514
# TimeOfDay_Afternoon 0.128639
# Wind speed 0.121108
# Holiday_No Holiday 0.072338
# Seasons_Spring 0.022888
# day 0.022291
# TimeOfDay_Morning -0.081115
# Rainfall -0.123074
# Snowfall -0.141804
# Humidity -0.199780
# Seasons_Winter -0.424925
# Name: Rented Bike Count, dtype: float64
위 상관관계를 보면 온도가 매우 큰 상관관계를 가짐을 알 수 있다.
- 종속변수와의 상관관계는 좋음.
그러나 높은 상관관계를 가진 컬럼의 경우 제거해야할 경우도 있는데, 다중공선성 문제가 발생할 수 있기 때문이다.
다중 공선성(Multicollinearity)
회귀 분석에서 독립 변수들(설명 변수)간에 강한 상관관관계(종속 변수 X!!) 가 존재하는 현상
- 각 독립변수가 종속변수에 미치는 개별적 영향을 추정하기 힘들어짐
- 추정치가 불안정해져 작은 데이터 변화에도 크게 영향을 줌
- 위 두이유로 예측 성능 저하, 해석의 신뢰성이 감소할 수 있음.
따라서 각각의 컬럼들의 상관계수를 파악해서 제거해주어야함.
plt.figure(figsize=(16, 12))
sns.heatmap(correlation_matrix, annot=True, fmt='.2f', cmap='coolwarm')
plt.title('Correlation Matrix')
plt.show()

위의 히트맵에서 보면 온도와 이슬점의 관계. 온도와 겨울과의 상관관계가 매우 높음을 알 수 있다.
- 그런데 제거해야할 기준은 뭘까?
VIF(Variance Inflation Factor)
한 독립변수가 다른 독립변수들에 의해 얼마나 잘 설명되는지 나타내는 값.
- 해당 변수가 사실상 다른 변수들의 조합은 아닌가를 수치로 보여줌.
기준
- VIF < 5: 문제 없음
- 5 ≤ VIF < 10: 주의해야함
- 10 ≤ VIF: 다중공선성 의심(조치 고려해야 함)
from statsmodels.stats.outliers_influence import variance_inflation_factor
x = bike_df.drop('Rented Bike Count', axis=1)# 타겟 변수 제거
x = x.select_dtypes(include=['number']) # VIF는 수치형 데이터에 대해서만 계산 가능
x = x.astype(float) # VIF 계산을 위해 float 타입으로 변환
vif_df = pd.DataFrame({
'Feature': x.columns,
'VIF': [variance_inflation_factor(x.values, i) for i in range(x.shape[1])]# 각 피처에 대한 VIF 계산
}).sort_values(by='VIF', ascending=False) # VIF 수치가 높은 순서대로 정렬
vif_df
| / | Feature | VIF |
| 9 | year | 407.025112 |
| 1 | Temperature | 188.666573 |
| 2 | Humidity | 187.533688 |
| 5 | Dew point temperature | 126.954261 |
| 4 | Visibility | 10.788995 |
| 10 | month | 5.108772 |
| 3 | Wind speed | 4.890096 |
| 0 | Hour | 4.458880 |
| 11 | day | 4.379818 |
| 6 | Solar Radiation | 2.904971 |
| 8 | Snowfall | 1.155412 |
| 7 | Rainfall | 1.103386 |
각 컬럼에 대해 VIF를 계산한다. (statsmodels의 variance_inflation_factor를 사용
- year: date에서 파생변수를 만들었음(동일한 애가 있음)
- 온도, 이슬점, 습도, 시야 등은 VIF가 높아 조치를 취해주어야한다.
bike_df = bike_df.drop(['Dew point temperature', 'Hour', 'Humidity'], ['year'], axis=1)
bike_df.head()
- 위처럼 제거해 주고 난 뒤 VIF를 확인하면
/ Feature VIF 2 Visibility 5.247050 6 month 4.211105 1 Wind speed 3.807370 7 day 3.292291 0 Temperature 2.758183 3 Solar Radiation 1.914448 5 Snowfall 1.116980 4 Rainfall 1.046290
- 위와 같이 10이상의 VIF는 없는것을 확인할 수 있다.
학습
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.2, random_state=42)
- 해당 컬럼들을 이용해서 모델을 나눠준다. (train과 test를 나눠줌)
결정트리(Decision Tree)
데이터 기반으로 의사결정을 수행하는 트리구조의 예측모델.
- 각 노드는 특정 특성의 조건에 따라 가지로 분기되어 최종으로 리프노드에 도달해 예측 결과를 도출
- 분류, 회귀 문제에 사용되어 데이터의 패턴을 직관적으로 시각화할 수 있다.
- 너무 깊어지면 과적합 문제가 발생할 수 있어 가지치기나 최대깊이 설정등으로 제어한다.
- 알고리즘의 트리구조임
원리
- 전체 데이터셋을 하나의 노드로 시작
- 최적의 특성, 분할기준을 찾아 첫번째 분할을 실행한다.
- 분류문제: Gini 불순도(Gini Impurity), 엔트로피(entropy)사용
- 회귀문제: MSE(평균 제곱 오차), MAE(절대 평균 오차)사용
- 각 하위 노드에 대해 위 과정 반봅
- 이 과정을 통해 트리는 여러 깊이로 성장
- 노드가 더 나눌 수 없거나 특정 조건(max_depth, min_samples, split)을 만족하면 종료(리프노드)
- 분류: 가장 많은 클래스가 있는 클래스가 예측값 회귀: 평균값이 예측값
지니 불순도
한 노드의 데이터 순수도를 측정,
- 한 노드에 있는 샘플이 동일한 클래스에 속할 확률이 높으면 불순도 저하.(노드의 엔트로피)
- 엔트로피는 데이터가 균등하게 분포되면 최대값.
DecisionTreeRegressor
주어진 데이터를 반복적으로 분할하여 예측을 수행
- 각 분할은 예측하는데 가장 적합한 값을 찾기 위해 이루어진다.
- 이를 통해 데이터를 점차 더 작은 부분으로 나누고, 각 부분에서 평균값을 예측값으로 사용한다.
목표
- 두 그룹의 MSE가 능한 한 낮도록 만드는것. 즉, MSE가 최소화 되도록 분할점을 찾는다.


from sklearn.tree import DecisionTreeRegressor
dt_reg = DecisionTreeRegressor(random_state=42)
dt_reg.fit(X_train, y_train)
y_pred = dt_reg.predict(X_test)
sns.scatterplot(x=y_test, y=y_pred, alpha=0.3)

예측하고 결과값을 scatterplot으로 찍으면 위와 같이 출력되는데.
이게 과연 잘 맞춘걸까?
- 대충보면 어느정도 값이 선형을 그리므로 잘 맞은것 같아보이긴한다.
원래 분류문제는 accuracy가 있어서 눈에띄게 확인이 가능하다. 하지만 회귀 문제의 경우 지표가 MSE나 RMSE를 확인한다.
from sklearn.metrics import root_mean_squared_error
root_mean_squared_error(y_test, y_pred)
#393.74930649113867
결정트리는 위와 같은 RMSE를 나타낸다.
비교를 위해 LinearRegression을 사용하면
from sklearn.linear_model import LinearRegression
lr_reg = LinearRegression()
lr_reg.fit(X_train, y_train)
pred2 = lr_reg.fit(X_train, y_train).predict(X_test)
sns.scatterplot(x=y_test, y=pred2, alpha=0.3)

root_mean_squared_error(y_test, pred2)
# 433.9205216180732
위와 같은 결과가 나온다.
decision트리가 rmse값이 더 작으므로 오차가 적다 즉, 더 잘 맞췄다.
하이퍼파라미터 튜닝
dt_reg = DecisionTreeRegressor(max_depth=50, min_samples_leaf=30, random_state=42)
decision트리의 하이퍼파라미터는 위와 같이 구성된다.
max_depth : 최대 깊이, 나누어져 내려가는 트리의 최대 깊이를 나타낸다.
min_samples_leaf: 최소 리프 크기, 트리를 나눌때 리프가 정해진 크기가 나오면 정지.
하이퍼 파라미터를 계속 수정하면서 오차를 고쳐나가보면
dt_reg = DecisionTreeRegressor(max_depth=10, min_samples_leaf=13, random_state=42)
dt_reg.fit(X_train, y_train)
y_pred = dt_reg.predict(X_test)
sns.scatterplot(x=y_test, y=y_pred, alpha=0.3)
root_mean_squared_error(y_test, y_pred)
# 319.2356988155453

위와 같이 성능이 좋아진 것을 확인할 수 있다.
decision트리가 어떤 결과를 거쳤는지 확인하기
from sklearn.tree import plot_tree
plt.figure(figsize=(24,12))
plot_tree(dt_reg, fontsize=10, feature_names=X_train.columns, max_depth=5)
plt.show()

sklearn에서 제공하는 plot_tree메서드를 이용하면, decision트리의 과정을 볼 수 있다.
랜덤포레스트(강한 학습기)
from sklearn.ensemble import RandomForestRegressor
rf_reg = RandomForestRegressor(random_state=42)
rf_reg.fit(X_train, y_train)
y_pred = rf_reg.predict(X_test)
sns.scatterplot(x=y_test, y=y_pred, alpha=0.3)
root_mean_squared_error(y_test, y_pred)
# 283.90004524006025

- 랜덤포레스트는 결정트리(약한학습기)를 여러개 만들어서 사용하는 것. 즉 성능이 좋을 수 밖에 없다.
- 그러나 항상 좋은 모델을 쓰는 것보다 적절한 모델을 쓰는것이 더 중요하다.
- 알뜰하게 최적의 값을 뽑는것.
피처 중요도(랜덤포레스트의 특성)
rf_reg.feature_importances_
# array([0.33120064, 0.03555859, 0.04532136, 0.18913849, 0.06638298,
# 0.00104838, 0.03108891, 0.03576222, 0.00366982, 0.00175583,
# 0.01641125, 0.00208089, 0.08394038, 0.00671751, 0.00638788,
# 0.14353488])
위는 각 피처의 중요도를 나타낸 값이다. (컬럼 순서대로)
이걸 데이터프레임으로 표시하면
feature_imp = pd.DataFrame({
'Feature': X_train.columns,
'Importance': rf_reg.feature_importances_
})
feature_imp.sort_values(by='Importance', ascending=False)
| / | Feature | Importance |
| 0 | Temperature | 0.331201 |
| 3 | Solar Radiation | 0.189138 |
| 15 | TimeOfDay_Evening | 0.143535 |
| 12 | Functioning Day_Yes | 0.083940 |
| 4 | Rainfall | 0.066383 |
| 2 | Visibility | 0.045321 |
| 7 | day | 0.035762 |
| 1 | Wind speed | 0.035559 |
| 6 | month | 0.031089 |
| 10 | Seasons_Winter | 0.016411 |
| 13 | TimeOfDay_Morning | 0.006718 |
| 14 | TimeOfDay_Afternoon | 0.006388 |
| 8 | Seasons_Spring | 0.003670 |
| 11 | Holiday_No Holiday | 0.002081 |
| 9 | Seasons_Summer | 0.001756 |
| 5 | Snowfall | 0.001048 |
위와 같이 컬럼 중요도를 뽑아낼 수 있다.
'AI공부 > 머신러닝' 카테고리의 다른 글
| 17. 호텔 수요 예측 2(모델 학습, 스케일링, 예측) (1) | 2026.01.11 |
|---|---|
| 16. 호텔 예약 수요 데이터셋 1(EDA, 인코딩) (0) | 2026.01.10 |
| 14. 서울 따릉이 대여 수요 예측 (0) | 2026.01.06 |
| 13. 자전거 대여 수요 예측 (0) | 2026.01.02 |
| 12. 주택 임대료 예측 2 (0) | 2025.12.30 |