머신러닝·딥러닝 문제해결 전략 책을 읽으면서
Kaggle 경진대회 코드와 문제해결 전략을 정리한 글
베이스라인 모델 전체 프로세스
1. 데이터 불러오기
2. (기본적인) 피처 엔지니어링
3. 평가지표 계산 함수 작성
4. 모델 훈련
5. 성능 검증
6. 제출
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')
# 훈련 데이터에서 weather가 4가 아닌 데이터만 추출
train = train[train['weather'] != 4]
훈련 데이터 : 10,886 행
테스트 데이터 : 6,493 행
총 데이터 : 17,379 행
weather가 4인 데이터를 제거했으니(1개 있음) 최종적으로 17,378행
all_data_temp = pd.concat([train, test])
all_data_temp
datetime | season | holiday | workingday | weather | temp | atemp | humidity | windspeed | casual | registered | count | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2011-01-01 00:00:00 | 1 | 0 | 0 | 1 | 9.84 | 14.395 | 81 | 0.0000 | 3.0 | 13.0 | 16.0 |
1 | 2011-01-01 01:00:00 | 1 | 0 | 0 | 1 | 9.02 | 13.635 | 80 | 0.0000 | 8.0 | 32.0 | 40.0 |
2 | 2011-01-01 02:00:00 | 1 | 0 | 0 | 1 | 9.02 | 13.635 | 80 | 0.0000 | 5.0 | 27.0 | 32.0 |
3 | 2011-01-01 03:00:00 | 1 | 0 | 0 | 1 | 9.84 | 14.395 | 75 | 0.0000 | 3.0 | 10.0 | 13.0 |
4 | 2011-01-01 04:00:00 | 1 | 0 | 0 | 1 | 9.84 | 14.395 | 75 | 0.0000 | 0.0 | 1.0 | 1.0 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
6488 | 2012-12-31 19:00:00 | 1 | 0 | 1 | 2 | 10.66 | 12.880 | 60 | 11.0014 | NaN | NaN | NaN |
6489 | 2012-12-31 20:00:00 | 1 | 0 | 1 | 2 | 10.66 | 12.880 | 60 | 11.0014 | NaN | NaN | NaN |
6490 | 2012-12-31 21:00:00 | 1 | 0 | 1 | 1 | 10.66 | 12.880 | 60 | 11.0014 | NaN | NaN | NaN |
6491 | 2012-12-31 22:00:00 | 1 | 0 | 1 | 1 | 10.66 | 13.635 | 56 | 8.9981 | NaN | NaN | NaN |
6492 | 2012-12-31 23:00:00 | 1 | 0 | 1 | 1 | 10.66 | 13.635 | 65 | 8.9981 | NaN | NaN | NaN |
17378 rows × 12 columns
# 원래 데이터의 인덱스를 무시하고 이어붙이려면 ignore_index=True를 전달
all_data = pd.concat([train, test], ignore_index=True)
all_data
datetime | season | holiday | workingday | weather | temp | atemp | humidity | windspeed | casual | registered | count | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2011-01-01 00:00:00 | 1 | 0 | 0 | 1 | 9.84 | 14.395 | 81 | 0.0000 | 3.0 | 13.0 | 16.0 |
1 | 2011-01-01 01:00:00 | 1 | 0 | 0 | 1 | 9.02 | 13.635 | 80 | 0.0000 | 8.0 | 32.0 | 40.0 |
2 | 2011-01-01 02:00:00 | 1 | 0 | 0 | 1 | 9.02 | 13.635 | 80 | 0.0000 | 5.0 | 27.0 | 32.0 |
3 | 2011-01-01 03:00:00 | 1 | 0 | 0 | 1 | 9.84 | 14.395 | 75 | 0.0000 | 3.0 | 10.0 | 13.0 |
4 | 2011-01-01 04:00:00 | 1 | 0 | 0 | 1 | 9.84 | 14.395 | 75 | 0.0000 | 0.0 | 1.0 | 1.0 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
17373 | 2012-12-31 19:00:00 | 1 | 0 | 1 | 2 | 10.66 | 12.880 | 60 | 11.0014 | NaN | NaN | NaN |
17374 | 2012-12-31 20:00:00 | 1 | 0 | 1 | 2 | 10.66 | 12.880 | 60 | 11.0014 | NaN | NaN | NaN |
17375 | 2012-12-31 21:00:00 | 1 | 0 | 1 | 1 | 10.66 | 12.880 | 60 | 11.0014 | NaN | NaN | NaN |
17376 | 2012-12-31 22:00:00 | 1 | 0 | 1 | 1 | 10.66 | 13.635 | 56 | 8.9981 | NaN | NaN | NaN |
17377 | 2012-12-31 23:00:00 | 1 | 0 | 1 | 1 | 10.66 | 13.635 | 65 | 8.9981 | NaN | NaN | NaN |
17378 rows × 12 columns
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())
drop_features = ['casual', 'registered', 'datetime', 'date', 'windspeed', 'month']
all_data = all_data.drop(drop_features, axis=1)
피처 선택(feature selection) : 모델링 시 데이터의 특징을 잘 나타내는 주요 피처만 선택하는 작업
# 훈련 데이터와 테스트 데이터 나누기
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'] # 타깃값
# 피처 엔지니어링 후의 훈련 데이터
X_train.head()
season | holiday | workingday | weather | temp | atemp | humidity | year | hour | weekday | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 0 | 0 | 1 | 9.84 | 14.395 | 81 | 2011 | 00 | 5 |
1 | 1 | 0 | 0 | 1 | 9.02 | 13.635 | 80 | 2011 | 01 | 5 |
2 | 1 | 0 | 0 | 1 | 9.02 | 13.635 | 80 | 2011 | 02 | 5 |
3 | 1 | 0 | 0 | 1 | 9.84 | 14.395 | 75 | 2011 | 03 | 5 |
4 | 1 | 0 | 0 | 1 | 9.84 | 14.395 | 75 | 2011 | 04 | 5 |
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 계산
output = np.sqrt(np.mean((log_true - log_pred)**2))
return output
실제 타깃값 y_true와 예측값 y_pred를 인수로 전달하면 RMSLE 수치를 반환하는 함수
# 사이킷런이 제공하는 LinearRegression 을 임포트하여 모델 생성
from sklearn.linear_model import LinearRegression
linear_reg_model = LinearRegression()
# 훈련 데이터로 모델 훈련
log_y = np.log(y) # 타깃값 로그 변환
linear_reg_model.fit(X_train, log_y) # 모델 훈련
LinearRegression()
선형 회귀 모델
# 모델 성능 검증을 위해 예측을 수행하는 코드
preds = linear_reg_model.predict(X_train)
코드를 실행하면 훈련된 선형 회귀 모델이 X_train 피처를 기반으로 타깃값을 예측
# 예측 결과로부터 훈련이 얼마나 잘 되었는지를 평가 : 타깃값 log_y와 예측 결과 preds 사이의 RMSLE 값을 구함
print(f'선형 회귀의 RMSLE 값 : {rmsle(log_y, preds, True):.4f}')
선형 회귀의 RMSLE 값 : 1.0205
주의할 점
1. 테스트 데이터로 예측한 결과를 이용해야 함. 앞서 모델 성능 검증 과정에서는 RMSLE 값을 구해보고자 훈련 데이터를 이용
2. 예측한 값에 지수변환을 해줘야 함. 현재 예측값이 count가 아니라 log(count)이기 때문
linearreg_preds = linear_reg_model.predict(X_test) # 테스트 데이터로 예측
submission['count'] = np.exp(linearreg_preds) # 지수변환
submission.to_csv('submission.csv', index=False) # 파일로 저장