| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
- 머신러닝
- 자연어처리
- python 기초
- RNN
- 기초
- 데이터엔지니어
- 데이터 시각화
- CLIP
- TTS
- UMAP
- 정보처리기사
- ASR
- 객체지향
- 알고리즘
- 힙정렬
- 생성형 인공지능
- 랭그래프
- 트랜스포머
- LangGraph
- RDBMS
- dementional reduction
- Python
- 캐글
- CNN
- Transformer
- python기초
- SQL
- 딥러닝
- 에이전트
- 소프트웨어 개발
- Today
- Total
수달이네 기술 블로그
13. 자전거 대여 수요 예측 본문
https://www.kaggle.com/competitions/2024-2-data-solution-ch-6-public
자전거를 얼마나 빌릴 건지 예측하는 회귀 문제(Regression)


- 머신러닝/딥러닝 문제해결 프로세스: 크게 ‘경진대회 이해’ → ‘탐색적 데이터 분석’ → ‘베이스라인 모델’ → ‘성능 개선’ 순으로 진행
- 타깃값 변환: 타깃값이 정규분포에 가까울수록 회귀 모델의 성능이 좋음. 한쪽으로 치우친 타깃값은 로그변환하면 정규분포에 가까워지고, 결괏값을 지수변환하면 원래 타깃값 형태로 복원됨.
- 이상치 제거: 훈련 데이터에서 이상치를 제거하면 일반화 성능이 좋아질 수 있음
- 파생 피처 추가: 기존 피처를 분해/조합하여 모델링에 도움되는 새로운 피처를 만들 수 있음
- 피처 제거: 반대로 불필요한 피처를 제거하면 성능도 좋아지고, 훈련 속도도 빨라짐
- 선형회귀, 릿지, 라쏘 모델: 회귀 문제를 푸는 대표적인 모델, but 너무 기본적이라 실전에서 단독으로 최상의 성능을 기대하기는 어려움
- 랜덤 포레스트 회귀 모델: 여러 모델을 묶어 (대체로) 더 나은 성능을 이끌어내는 간단하고 유용한 기법입니다.
- 그리드서치: 교차 검증으로 최적의 하이퍼파라미터 값을 찾아주는 기법
주제
워싱턴 D.C자전거 무인 대여 시스템 과거 기록을 바탕으로 향후 자전거 대여 수요 예측
- 2011년부터 2012년까지 2년간 자전거 대여 데이터 + 날씨 데이터 (대여 날짜, 시간, 요일, 계절, 날씨, 실제 온도, 체감 온도, 습도, 풍속, 회원 여부)
- 훈련데이터: 매달 1~19일
- 테스트데이터: 매달 20~월말
- 테스트데이터, 훈련데이터를 랜덤으로 나누거나 비율대로 막 나누는 경우 오히려 섞일 가능성이 존재.
탐색적 데이터 분석
- 주어진 데이터의 구성 분석
판다스를 이용하여 훈련, 테스트, 제출 샘플 데이터를 DataFrame 형태로 불러온다.
import numpy as np # 넘파이 임포트
import pandas as pd # 판다스 임포트
data_path = '/kaggle/input/bike-sharing-demand/' # 데이터 경로
train = pd.read_csv(data_path + 'train.csv') # 훈련 데이터
test = pd.read_csv(data_path + 'test.csv') # 테스트 데이터
submission = pd.read_csv(data_path + 'sampleSubmission.csv') # 제출 샘플 데이터
train.shape, test.shape
#((10886, 12), (6493, 9))
train.head()
- 머신러닝/딥러닝 문제해결 프로세스: 크게 ‘경진대회 이해’ → ‘탐색적 데이터 분석’ → ‘베이스라인 모델’ → ‘성능 개선’ 순으로 진행
- 타깃값 변환: 타깃값이 정규분포에 가까울수록 회귀 모델의 성능이 좋음. 한쪽으로 치우친 타깃값은 로그변환하면 정규분포에 가까워지고, 결괏값을 지수변환하면 원래 타깃값 형태로 복원됨.
- 이상치 제거: 훈련 데이터에서 이상치를 제거하면 일반화 성능이 좋아질 수 있음
- 파생 피처 추가: 기존 피처를 분해/조합하여 모델링에 도움되는 새로운 피처를 만들 수 있음
- 피처 제거: 반대로 불필요한 피처를 제거하면 성능도 좋아지고, 훈련 속도도 빨라짐
- 선형회귀, 릿지, 라쏘 모델: 회귀 문제를 푸는 대표적인 모델, but 너무 기본적이라 실전에서 단독으로 최상의 성능을 기대하기는 어려움
- 랜덤 포레스트 회귀 모델: 여러 모델을 묶어 (대체로) 더 나은 성능을 이끌어내는 간단하고 유용한 기법입니다.
- 그리드서치: 교차 검증으로 최적의 하이퍼파라미터 값을 찾아주는 기법
주제
워싱턴 D.C자전거 무인 대여 시스템 과거 기록을 바탕으로 향후 자전거 대여 수요 예측
- 2011년부터 2012년까지 2년간 자전거 대여 데이터 + 날씨 데이터 (대여 날짜, 시간, 요일, 계절, 날씨, 실제 온도, 체감 온도, 습도, 풍속, 회원 여부)
- 훈련데이터: 매달 1~19일
- 테스트데이터: 매달 20~월말
- 테스트데이터, 훈련데이터를 랜덤으로 나누거나 비율대로 막 나누는 경우 오히려 섞일 가능성이 존재.
탐색적 데이터 분석
- 주어진 데이터의 구성 분석
판다스를 이용하여 훈련, 테스트, 제출 샘플 데이터를 DataFrame 형태로 불러온다.
import numpy as np # 넘파이 임포트
import pandas as pd # 판다스 임포트
data_path = '/kaggle/input/bike-sharing-demand/' # 데이터 경로
train = pd.read_csv(data_path + 'train.csv') # 훈련 데이터
test = pd.read_csv(data_path + 'test.csv') # 테스트 데이터
submission = pd.read_csv(data_path + 'sampleSubmission.csv') # 제출 샘플 데이터
train.shape, test.shape
#((10886, 12), (6493, 9))
train.head()
submission.head()

데이터 타입 파악, 결측값 개수 파악
train.info()
'''
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 datetime 10886 non-null object
1 season 10886 non-null int64
2 holiday 10886 non-null int64
3 workingday 10886 non-null int64
4 weather 10886 non-null int64
5 temp 10886 non-null float64
6 atemp 10886 non-null float64
7 humidity 10886 non-null int64
8 windspeed 10886 non-null float64
9 casual 10886 non-null int64
10 registered 10886 non-null int64
11 count 10886 non-null int64
'''
test.info()
'''
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 datetime 6493 non-null object
1 season 6493 non-null int64
2 holiday 6493 non-null int64
3 workingday 6493 non-null int64
4 weather 6493 non-null int64
5 temp 6493 non-null float64
6 atemp 6493 non-null float64
7 humidity 6493 non-null int64
8 windspeed 6493 non-null float64
'''
데이터 시각화
datetime피처를 세부 구성요소로 나누기
print(train['datetime'][100]) # datetime 100번째 원소
print(train['datetime'][100].split()) # 공백 기준으로 문자열 나누기
print(train['datetime'][100].split()[0]) # 날짜
print(train['datetime'][100].split()[1]) # 시간
print(train['datetime'][100].split()[0]) # 날짜
print(train['datetime'][100].split()[0].split("-")) # "-" 기준으로 문자열 나누기
print(train['datetime'][100].split()[0].split("-")[0]) # 연도
print(train['datetime'][100].split()[0].split("-")[1]) # 월
print(train['datetime'][100].split()[0].split("-")[2]) # 일
print(train['datetime'][100].split()[1]) # 시간
print(train['datetime'][100].split()[1].split(":")) # ":" 기준으로 문자열 나누기
print(train['datetime'][100].split()[1].split(":")[0]) # 시간
print(train['datetime'][100].split()[1].split(":")[1]) # 분
print(train['datetime'][100].split()[1].split(":")[2]) # 초
피처엔지니어링(기존 피처에서 파생된 피처(파생피처)만들기)
판다스의 apply()함수로 앞의 나눈 시간을 피처로 생성
train['date'] = train['datetime'].apply(lambda x: x.split()[0]) # 날짜 피처 생성
# 연도, 월, 일, 시, 분, 초 피처를 차례로 생성
train['year'] = train['datetime'].apply(lambda x: x.split()[0].split('-')[0])
train['month'] = train['datetime'].apply(lambda x: x.split()[0].split('-')[1])
train['day'] = train['datetime'].apply(lambda x: x.split()[0].split('-')[2])
train['hour'] = train['datetime'].apply(lambda x: x.split()[1].split(':')[0])
train['minute'] = train['datetime'].apply(lambda x:
x.split()[1].split(':')[1])
train['second'] = train['datetime'].apply(lambda x:
x.split()[1].split(':')[2])
요일 피처도 생성
from datetime import datetime # datetime 라이브러리 임포트
import calendar
print(train['date'][100]) # 날짜
print(datetime.strptime(train['date'][100], '%Y-%m-%d')) # datetime 타입으로 변경
# 정수로 요일 반환
print(datetime.strptime(train['date'][100], '%Y-%m-%d').weekday())
# 문자열로 요일 반환
print(calendar.day_name[datetime.strptime(train['date'][100], '%Y-%m-%d').weekday()])
계절, 날씨 피처도 추가
train['season'] = train['season'].map({1: 'Spring',
2: 'Summer',
3: 'Fall',
4: 'Winter' })
train['weather'] = train['weather'].map({1: 'Clear',
2: 'Mist, Few clouds',
3: 'Light Snow, Rain, Thunderstorm',
4: 'Heavy Rain, Thunderstorm, Snow,Fog'})
시각화
import seaborn as sns
import matplotlib as mpl
import matplotlib.pyplot as plt
%matplotlib inline
mpl.rc('font', size=15) # 폰트 크기를 15로 설정
sns.displot(train['count']); # 분포도 출력
타깃값이 정규분포를 따르는게 좋음. (로그 변환)
- 모델이 잘 학습하는 형태이다.

이거에서
sns.displot(np.log(train['count']));

- 나중에 지수변환해주어야함.

# 스텝 1 : m행 n열 Figure 준비
figure, axes = plt.subplots(nrows=2, ncols=2) # 2행 2열
plt.tight_layout()
figure.set_size_inches(10, 10)
# 스텝 2 : 서브플롯 할당
# 계절, 날씨, 공휴일, 근무일별 대여 수량 박스플롯
sns.boxplot(x='season', y='count', data=train, ax=axes[0, 0])
sns.boxplot(x='weather', y='count', data=train, ax=axes[0, 1])
sns.boxplot(x='holiday', y='count', data=train, ax=axes[1, 0])
sns.boxplot(x='workingday', y='count', data=train, ax=axes[1, 1])
# 스텝 3 : 세부 설정
# 3-1 서브플롯에 제목 달기
axes[0, 0].set(title='Box Plot On Count Across Season')
axes[0, 1].set(title='Box Plot On Count Across Weather')
axes[1, 0].set(title='Box Plot On Count Across Holiday')
axes[1, 1].set(title='Box Plot On Count Across Working Day')
# 3-2 x축 라벨 겹침 해결
axes[0, 1].tick_params(axis='x', labelrotation=10) # 10도 회전

연도별은 점차 늘고 있구나
날이 따뜻할 수록 대여가 많구나
day피처는 훈련 데이터와 테스트데이터는 피처가 서로 달라 사용 할 수 없구나
시간별은 출퇴근, 등하교때 많구나
분과 초는 의미
가 없으니 제거해도 괜찮구나
박스플롯
# 스텝 1 : m행 n열 Figure 준비
figure, axes = plt.subplots(nrows=2, ncols=2) # 2행 2열
plt.tight_layout()
figure.set_size_inches(10, 10)
# 스텝 2 : 서브플롯 할당
# 계절, 날씨, 공휴일, 근무일별 대여 수량 박스플롯
sns.boxplot(x='season', y='count', data=train, ax=axes[0, 0])
sns.boxplot(x='weather', y='count', data=train, ax=axes[0, 1])
sns.boxplot(x='holiday', y='count', data=train, ax=axes[1, 0])
sns.boxplot(x='workingday', y='count', data=train, ax=axes[1, 1])
# 스텝 3 : 세부 설정
# 3-1 서브플롯에 제목 달기
axes[0, 0].set(title='Box Plot On Count Across Season')
axes[0, 1].set(title='Box Plot On Count Across Weather')
axes[1, 0].set(title='Box Plot On Count Across Holiday')
axes[1, 1].set(title='Box Plot On Count Across Working Day')
# 3-2 x축 라벨 겹침 해결
axes[0, 1].tick_params(axis='x', labelrotation=10) # 10도 회전

- 계절별 대여 수량
- 날씨별 대여 수량(좋을수록 많다)
- 공휴일 여부에 따른(공휴일이 아닐때 이상치가 많다)
- 근무일 여부에 따른 수량(근무일일때 이상치가 많다)
포인트플롯
# 스텝 1 : m행 n열 Figure 준비
mpl.rc('font', size=11)
figure, axes = plt.subplots(nrows=5) # 5행 1열
figure.set_size_inches(12, 18)
# 스텝 2 : 서브플롯 할당
# 근무일, 공휴일, 요일, 계절, 날씨에 따른 시간대별 평균 대여 수량 포인트플롯
sns.pointplot(x='hour', y='count', data=train, hue='workingday', ax=axes[0])
sns.pointplot(x='hour', y='count', data=train, hue='holiday', ax=axes[1])
sns.pointplot(x='hour', y='count', data=train, hue='weekday', ax=axes[2])
sns.pointplot(x='hour', y='count', data=train, hue='season', ax=axes[3])
sns.pointplot(x='hour', y='count', data=train, hue='weather', ax=axes[4]);

공휴일일때는 11시~3시사이가 많다
공휴일이 아닐때는 출퇴근 시간에 많았다
회귀선 포함 산점도
# 스텝 1 : m행 n열 Figure 준비
mpl.rc('font', size=15)
figure, axes = plt.subplots(nrows=2, ncols=2) # 2행 2열
plt.tight_layout()
figure.set_size_inches(7, 6)
# 스텝 2 : 서브플롯 할당
# 온도, 체감 온도, 풍속, 습도 별 대여 수량 산점도 그래프
sns.regplot(x='temp', y='count', data=train, ax=axes[0, 0],
scatter_kws={'alpha': 0.2}, line_kws={'color': 'blue'})
sns.regplot(x='atemp', y='count', data=train, ax=axes[0, 1],
scatter_kws={'alpha': 0.2}, line_kws={'color': 'blue'})
sns.regplot(x='windspeed', y='count', data=train, ax=axes[1, 0],
scatter_kws={'alpha': 0.2}, line_kws={'color': 'blue'})
sns.regplot(x='humidity', y='count', data=train, ax=axes[1, 1],
scatter_kws={'alpha': 0.2}, line_kws={'color': 'blue'});

온도, 체감온도가 높을수록 대여수량이 많음
풍속의 경우 결측치가 너무 많아서 제거
습도가 낮을수록 대여수량이 많음
히트맵
train[['temp', 'atemp', 'humidity', 'windspeed', 'count']].corr()

조합이 너무 많음. 따라서 히트맵이 필요!
# 피처 간 상관관계 매트릭스
corrMat = train[['temp', 'atemp', 'humidity', 'windspeed', 'count']].corr()
fig, ax= plt.subplots()
fig.set_size_inches(10, 10)
sns.heatmap(corrMat, annot=True) # 상관관계 히트맵 그리기
ax.set(title='Heatmap of Numerical Data');

상관관계가 큰것을 한눈에 파악할 수 있다
베이스라인 모델

뼈대가 되는 기본적인 모델 선정
1. 피처 엔지니어링
데이터를 변환하는 작업
import pandas as pd
# 데이터 경로
data_path = '/kaggle/input/bike-sharing-demand/'
train = pd.read_csv(data_path + 'train.csv')
test = pd.read_csv(data_path + 'test.csv')
submission = pd.read_csv(data_path + 'sampleSubmission.csv')
- 데이터를 불러오는 코드

훈련 데이터, 테스트 데이터를 병합 후, 타입을 변경하거나, 일부 데이터 삭제, 추가한다.
- 이후엔 다시 나눠줘야한다.
1) 이상치 제거
데이터를 합치기 전 이상치를 제거한다
# 훈련 데이터에서 weather가 4가 아닌 데이터만 추출
train = train[train['weather'] != 4]
- 위는 폭우, 폭설인 날 자전거를 빌린 데이터
2) 데이터 합치기
all_data = pd.concat([train, test], ignore_index=True)
all_data
- 훈련데이터와 테스트 데이터에 같은 피처 엔지니어링(데이터를 변환할때 이상이 없어야하기 때문)을 적용
- 훈련데이터와 테스트 데이터의 차이를 알아야함.
3) 파생피처 추가
from datetime import datetime
# 날짜 피처 생성
all_data['date'] = all_data['datetime'].apply(lambda x: x.split()[0])
# 연도 피처 생성
all_data['year'] = all_data['datetime'].apply(lambda x: x.split()[0].split('-')[0])
# 월 피처 생성
all_data['month'] = all_data['datetime'].apply(lambda x: x.split()[0].split('-')[1])
# 시 피처 생성
all_data['hour'] = all_data['datetime'].apply(lambda x: x.split()[1].split(':')[0])
# 요일 피처 생성
all_data["weekday"] = all_data['date'].apply(lambda dateString : datetime.strptime(dateString,"%Y-%m-%d").weekday())
- 위에서 만들었던 추가 피처들을 데이터에 추가해준다.
4) 필요없는 피처 제거
- casual과 registered 피처는 테스트 데이터에 없으므로 제거(분석 정리 4)
- datetime 피처는 인덱스 역할이고, date 피처가 갖는 정보는 다른 피처들(year, month, day)에도 담겨 있기 때문에 datetime과 date 피처도 필요 없음(분석 정리 5, 6)
- season 피처가 month 피처의 대분류 성격이라 month 피처도 제거(분석 정리 7)
- windspeed 피처도 타깃값과 상관관계가 약해서 제거(분석 정리 11)
drop_features = ['casual', 'registered', 'datetime', 'date', 'windspeed', 'month']
all_data = all_data.drop(drop_features, axis=1)
# 위에서 말한 필요없는 데이터를 drop_features로 묶은 후 제거
- 탐색적 데이터 분석에서 얻은 인사이트를 활용해 의미 있는 피처와 불필요한 피처를 구분(피처 선택)
- 피처가 많다고 좋은게 아님
- 타깃값과 관련이 있는 피처를 적용하는게 중요
- 탐색 데이터 분석, 피처 중요도, 상관관계 매트릭스, 배경지식을 종합적으로 활용해야함.
5) 데이터 나누기
# 훈련 데이터와 테스트 데이터 나누기
X_train = all_data[~pd.isnull(all_data['count'])]
X_test = all_data[pd.isnull(all_data['count'])]
# 타깃값 count 제거
X_train = X_train.drop(['count'], axis=1)
X_test = X_test.drop(['count'], axis=1)
y = train['count'] # 타깃값
- 피처 엔지니어링 완료 후 훈련데이터와 테스트데이터를 다시 나눠줌
- 타깃값의 유무에 따라 나눴음
- count는 타깃값이므로 제거
6) 평가지표 계산 함수 작성
import numpy as np
def rmsle(y_true, y_pred, convertExp=True):
# 지수변환
if convertExp:
y_true = np.exp(y_true)
y_pred = np.exp(y_pred)
# 로그변환 후 결측값을 0으로 변환
log_true = np.nan_to_num(np.log(y_true+1))
log_pred = np.nan_to_num(np.log(y_pred+1))
# RMSLE RM계산
output = np.sqrt(np.mean((log_true - log_pred)**2))
return output

- 해당 경진대회의 평가지표인 RMSLE를 사용했다.
7) 모델 생성 후 훈련
from sklearn.linear_model import LinearRegression
linear_reg_model = LinearRegression() # 선형 회귀 모델 생성
log_y = np.log(y) # 타깃값 로그변환
linear_reg_model.fit(X_train, log_y) # 모델 훈련
- 가장 간단한 선형 회귀 모델인 LinearRegression을 활용함
- fit()는 사이킷런의 훈련 메서드이다.

- 피처와 타깃값의 최적 가중치(회귀 계수)를 찾는 과정
- 최적 가중치에서 새로운 데이터가 주어질때 타깃값을 추청하는 과정
8) 모델 성능 검증
preds = linear_reg_model.predict(X_train)
print (f'선형회귀의 RMSLE 값 : {rmsle(log_y, preds, True):.4f}')
#선형회귀의 RMSLE 값 : 1.0205
- 훈련된 모델로 예측 수행
- 위는 학습을 한 결과를 input으로 넣어서 실제 잘나오는지 확인한다.
- RMLSE를 계산해 실제로 예측이 잘되었는지 확인
9) 예측 결과 제출
linearreg_preds = linear_reg_model.predict(X_test) # 테스트 데이터로 예측
submission['count'] = np.exp(linearreg_preds) # 지수변환
submission.to_csv('submission.csv', index=False) # 파일로 저장
- to_csv는 DataFrame을 csv파일로 저장하는 함수
- 제출 결과도 확인
성능 개선
1. 릿지 회귀 모델
- L2 규제를 적용한 선형 회귀 모델
- 규제regularization란 모델이 훈련 데이터에 과대적합overfitting되지 않도록 해주는 방법
- 훈련 데이터에 과대적합되면 모델이 훈련 데이터에만 너무 잘 들어맞고, 테스트 데이터로는 제대로 예측하지 못함

- 모델 훈련 단계에서 하이퍼 파라미터 최적화 수행
- 성능이 만족스러울 때 까지 최적화(피처엔지니어링 포함)
1) 하이퍼 파라미터 최적화(모델 훈련)
모델이 가진 파라미터를 바꿔주는 것
그리드 서치

하이퍼 파라미터 최적화 기법중 하나, 격자처럼 촘촘히 순회하며 최적 파라미터 값을 찾음,
각 하이퍼 파라미터를 적용한 모델을 교차검증해 가장 좋은 성능을 찾음(여러가지를 테스트해봄)
아니면 수동으로 해야함.

from sklearn.linear_model import Ridge
from sklearn.model_selection import GridSearchCV
from sklearn import metrics
ridge_model = Ridge()
- 릿지 모델 생성 후
# 하이퍼파라미터 값 목록
ridge_params =
{'max_iter':[3000], 'alpha':[0.1, 1, 2, 3, 4, 10, 30, 100, 200, 300, 400, 800, 900, 1000]}
# 교차 검증용 평가 함수(RMSLE 점수 계산)
rmsle_scorer = metrics.make_scorer(rmsle, greater_is_better=False)
# 그리드서치(with 릿지) 객체 생성
gridsearch_ridge_model = GridSearchCV(estimator=ridge_model, # 릿지 모델
param_grid=ridge_params, # 하이퍼파라미터 값 목록
scoring=rmsle_scorer, # 평가지표
cv=5) # 교차검증 분할 수
- 그리드 서치 객체 생성
- 하이퍼 파라미터 값 목록(검증해볼 것)
- 대상 모델
- 교차 검증용 평가 수단(평가함수)
- 위의 3가지로 하이퍼 파라미터를 비교하여 최적을 찾는다.
- 그리드 서치 수행
- log_y = np.log(y) # 타깃값 로그변환 gridsearch_ridge_model.fit(X_train, log_y) # 훈련(그리드서치) print('최적 하이퍼파라미터 :', gridsearch_ridge_model.best_params_) #최적 하이퍼파라미터 : {'alpha': 0.1, 'max_iter': 3000}
- fit 메서드로 값을 순회하며 교차검증 평가지표 계산
- 이후 최적 하이퍼 파라미터를 찾음
2) 성능검증
# 예측
preds = gridsearch_ridge_model.best_estimator_.predict(X_train)
# 평가
print(f'릿지 회귀 RMSLE 값 : {rmsle(log_y, preds, True):.4f}')
2. 라쏘 회귀 모델
from sklearn.linear_model import Lasso
# 모델 생성
lasso_model = Lasso()
# 하이퍼파라미터 값 목록
lasso_alpha
= 1/np.array([0.1, 1, 2, 3, 4, 10, 30, 100, 200, 300, 400, 800, 900, 1000])
lasso_params = {'max_iter':[3000], 'alpha':lasso_alpha}
# 그리드서치(with 라쏘) 객체 생성
gridsearch_lasso_model = GridSearchCV(estimator=lasso_model,
param_grid=lasso_params,
scoring=rmsle_scorer,
cv=5)
# 그리드서치 수행
log_y = np.log(y)
gridsearch_lasso_model.fit(X_train, log_y)
전체 흐름은 릿지와 같음
# 예측
preds = gridsearch_lasso_model.best_estimator_.predict(X_train)
# 평가
print(f'라쏘 회귀 RMSLE 값 : {rmsle(log_y, preds, True):.4f}')
검증
3. 랜덤 포레스트 회귀 모델
from sklearn.ensemble import RandomForestRegressor
# 모델 생성
randomforest_model = RandomForestRegressor()
# 그리드서치 객체 생성
rf_params = {'random_state':[42], 'n_estimators':[100, 120, 140]}
gridsearch_random_forest_model = GridSearchCV(estimator=randomforest_model,
param_grid=rf_params,
scoring=rmsle_scorer,
cv=5)
# 그리드서치 수행
log_y = np.log(y)
gridsearch_random_forest_model.fit(X_train, log_y)
print('최적 하이퍼파라미터 :', gridsearch_random_forest_model.best_params_)
#최적 하이퍼파라미터 : {'n_estimators': 140, 'random_state': 42}
# 예측
preds = gridsearch_random_forest_model.best_estimator_.predict(X_train)
# 평가
print(f'랜덤 포레스트 회귀 RMSLE 값 : {rmsle(log_y, preds, True):.4f}')
#랜덤 포레스트 회귀 RMSLE 값: 0.1126
큰폭으로 개선되었음을 확인
# 예측
randomforest_preds = gridsearch_random_forest_model.best_estimator_.predict(X_test)
submission['count'] = np.exp(randomforest_preds) # 지수변환
submission.to_csv('submission.csv', index=False) # 예측 결과를 csv 파일로 저장
위처럼 이번엔 교과서에서 배우는 대로 자전거 수요 예측 모델을 구성해 보았다.
해당 지식을 바탕으로 다음엔 실제 예측 연습을 해볼 것이다.
주제는 악성 URL 판단으로 정했다.
'AI공부 > 머신러닝' 카테고리의 다른 글
| 15. 서울 따릉이 수요 예측2 (0) | 2026.01.09 |
|---|---|
| 14. 서울 따릉이 대여 수요 예측 (0) | 2026.01.06 |
| 12. 주택 임대료 예측 2 (0) | 2025.12.30 |
| 11. 주택 임대료 예측 (1) | 2025.12.29 |
| 10. Iris 데이터셋 예측(머신러닝 입문) (0) | 2025.12.28 |