파이썬을 통해서 자전거 수요 데이터를 사용해서 회귀 실습을 해보았습니다. 이번에는 똑같이 R을 사용해서 코드를 변경하고 비교해 가면서 공부를 해보겠습니다.
In
# 패키지 불러오기 #
library(lubridate)
library(MLmetrics)
library(caret)
library(stats)
library(dummies)
bike_data <- read.csv("C:\\Users\\User\\ML_Book\\bike_train.csv")
head(bike_data)
str(bike_data)
Out
datetime season holiday workingday weather temp atemp humidity windspeed casual registered count
1 2011-01-01 00:00:00 1 0 0 1 9.84 14.395 81 0.0000 3 13 16
2 2011-01-01 01:00:00 1 0 0 1 9.02 13.635 80 0.0000 8 32 40
3 2011-01-01 02:00:00 1 0 0 1 9.02 13.635 80 0.0000 5 27 32
4 2011-01-01 03:00:00 1 0 0 1 9.84 14.395 75 0.0000 3 10 13
5 2011-01-01 04:00:00 1 0 0 1 9.84 14.395 75 0.0000 0 1 1
6 2011-01-01 05:00:00 1 0 0 2 9.84 12.880 75 6.0032 0 1 1
'data.frame': 10886 obs. of 12 variables:
$ datetime : Factor w/ 10886 levels "2011-01-01 00:00:00",..: 1 2 3 4 5 6 7 8 9 10 ...
$ season : int 1 1 1 1 1 1 1 1 1 1 ...
$ holiday : int 0 0 0 0 0 0 0 0 0 0 ...
$ workingday: int 0 0 0 0 0 0 0 0 0 0 ...
$ weather : int 1 1 1 1 1 2 1 1 1 1 ...
$ temp : num 9.84 9.02 9.02 9.84 9.84 ...
$ atemp : num 14.4 13.6 13.6 14.4 14.4 ...
$ humidity : int 81 80 80 75 75 75 80 86 75 76 ...
$ windspeed : num 0 0 0 0 0 ...
$ casual : int 3 8 5 3 0 0 2 1 1 8 ...
$ registered: int 13 32 27 10 1 1 0 2 7 6 ...
$ count : int 16 40 32 13 1 1 2 3 8 14 ...
데이터를 살펴보면 NULL 데이터는 없으며 대부분 int와 float 숫자형이고 datetime 컬럼은 Factor형을 가지고 있습니다.
datetime 칼럼을 년, 월, 일, 시간으로 분리하도록 하겠습니다. R에서는 lubridate 패키지를 통해서 분리를 할 수 있습니다.
In
# 데이터 분리하기 #
year<-year(bike_data$datetime)
month<-month(bike_data$datetime)
day<-day(bike_data$datetime)
hour<-hour(bike_data$datetime)
bike_data<-cbind(bike_data,year, month, day, hour)
head(bike_data)
Out
datetime season holiday workingday weather temp atemp humidity windspeed casual registered count year month day hour
1 2011-01-01 00:00:00 1 0 0 1 9.84 14.395 81 0.0000 3 13 16 2011 1 1 0
2 2011-01-01 01:00:00 1 0 0 1 9.02 13.635 80 0.0000 8 32 40 2011 1 1 1
3 2011-01-01 02:00:00 1 0 0 1 9.02 13.635 80 0.0000 5 27 32 2011 1 1 2
4 2011-01-01 03:00:00 1 0 0 1 9.84 14.395 75 0.0000 3 10 13 2011 1 1 3
5 2011-01-01 04:00:00 1 0 0 1 9.84 14.395 75 0.0000 0 1 1 2011 1 1 4
6 2011-01-01 05:00:00 1 0 0 2 9.84 12.880 75 6.0032 0 1 1 2011 1 1 5
새로운 칼럼들이 추가된것을 확인하였습니다. 이제 datetime 컬럼은 삭제하도록 하겠습니다.
또한 casual+registered = count 이기 때문에 두 칼럼을 삭제하도록 하겠습니다.
In
# 필요없는 데이터 삭제하기
bike_data<-bike_data[,-1]
bike_data<-bike_data[,-9]
bike_data<-bike_data[,-9]
회귀 모델을 평가하는 방법은 종류가 다양합니다. 여기서는 RMSLE (Root Mean Squared Log
Error), MAE (Mean Absolue Error), RMSE (Root Mean Squared Error)을 사용하겠습니다.
In
# mae
mae_fun <- function(y,pred){
man<- mean(abs(y-pred))
return(man)
}
# rmse
rmse_fun <- function(y,pred){
rmse <- sqrt(mean((y-pred)**2))
return(rmse)
}
#rmsle
rmsle_fun <- function(y,pred){
log_y <- log1p(y)
log_pred <- log1p(abs(pred))
squared_error <- ((log_y -log_pred)**2)
rmsle <- sqrt(mean(squared_error))
return(rmsle)
}
다음과 같이 함수로 만들었습니다. 편리를 위하여 세가지의 성능 측정을 결합하여 evaluate라는 함수로 만들어서 사용하도록 하겠습니다.
In
# 성능 측정 함수 결합
evaluate <- function(y,pred){
mae_val <- mae_fun(y,pred)
rmse_val <- rmse_fun(y,pred)
rmsle_val <- rmsle_fun(y,pred)
cat('MAE:',round(mae_val,3), 'RMSE:',round(rmse_val), 'RMSLE:',round(rmsle_val,3))
}
자 이제 데이터를 학습과 테스트 데이터셋으로 분리하도록 하겠습니다.
In
# 학습 테스트 분리하기
split<- createDataPartition(y=bike_data$count, p=0.7, list=F)
train<-bike_data[split,]
test<-bike_data[-split,]
다음으로 모델을 학습시키도록 하겠습니다.
In
# 모델 학습하기
lr_reg = lm(count~., data=bike_data)
pred <- predict(lr_reg,test)
이제 evaluate 함수를 사용해서 성능을 측정해보도록 하겠습니다.
In
evaluate(test$count,pred)
Out
MAE: 105.408 RMSE: 140 RMSLE: 1.202
다음과 같은 결과가 나왔습니다. 그렇게 좋은 결과는 아닌 것 같습니다.
데이터의 이상점을 파악해보기 위해서 먼저 target 변수를 살펴보도록 하겠습니다.
그래프를 보면 정규분포의 형태를 이루지 않게 되어있습니다. 0~200에서 많이 분포되어 데이터가 왜곡되어 있음을 알 수 있습니다. 이렇게 왜곡된 형태는 로그를 적용해 변환을 해주는 것이 필요합니다.
여기서 주의!! 해야할 부분은 테스트의 적용을 할때는 다시 원래 상태로 돌려서 적용을 해주어야 합니다!!
In
bike_data_log<-bike_data
bike_data_log$count<-log1p(bike_data_log$count)
hist(bike_data_log$count, col = 'aquamarine')
Out
로그 변환 결과 어느정도 왜곡 정도가 많이 향상 되어있습니다. 이 데이터를 통해서 다시 학습을 해보도록 하겠습니다.
In
bike_data_log<-bike_data
bike_data_log$count<-log1p(bike_data_log$count)
hist(bike_data_log$count, col = 'aquamarine')
split_log<- createDataPartition(y=bike_data_log$count, p=0.7, list=F)
train_log<-bike_data_log[split,]
test_log<-bike_data_log[-split,]
lr_reg_log = lm(count~., data=bike_data_log)
pred_log <- predict(lr_reg_log,test_log)
# 원래 상태로 바꿔주기
y_test_exp <- expm1(test_log$count)
pred_exp <- expm1(pred_log)
evaluate(y_test_exp,pred_exp)
Out
MAE: 107.65 RMSE: 161 RMSLE: 1.016
MAE: 105.408 RMSE: 140 RMSLE: 1.202
RMSE값은 줄었지만 RMSLE는 늘어나는 결과가 나왔습니다.
Year은 연도를 의미하기 때문에 카테고리형 이지만 숫자형 값으로 입력되어 있습니다.
이러한 숫자형 카테고리 값을 선형 회귀에 사용할 경우 회귀 계수를 연살할 때 이 숫자형 값에 크게 영향을 받는 경우가 발생합니다. 그래서 이러한 피처들을 더미변수를 사용하여 변화를 해주어야 합니다.
library(dummies)를 사용해서 컬럼들을 모두 원=핫 인코딩을 하여 다시 성능을 평가해보도록 하겠습니다.
In
bike_data$season<-as.factor(bike_data$season)
bike_data$weather<-as.factor(bike_data$weather)
bike_data$workingday<-as.factor(bike_data$workingday)
bike_data$year<-as.factor(bike_data$year)
bike_data$month<-as.factor(bike_data$month)
bike_data$day<-as.factor(bike_data$day)
bike_data$hour<-as.factor(bike_data$hour)
bike_data$holiday<-as.factor(bike_data$holiday)
dum_data<-dummy.data.frame(bike_data)
head(dum_data,10)
Out
season1 season2 season3 season4 holiday0 holiday1 workingday0 workingday1 weather1 weather2 weather3 weather4
1 1 0 0 0 1 0 1 0 1 0 0 0
2 1 0 0 0 1 0 1 0 1 0 0 0
3 1 0 0 0 1 0 1 0 1 0 0 0
4 1 0 0 0 1 0 1 0 1 0 0 0
5 1 0 0 0 1 0 1 0 1 0 0 0
6 1 0 0 0 1 0 1 0 0 1 0 0
7 1 0 0 0 1 0 1 0 1 0 0 0
8 1 0 0 0 1 0 1 0 1 0 0 0
9 1 0 0 0 1 0 1 0 1 0 0 0
10 1 0 0 0 1 0 1 0 1 0 0 0
추가작성 필요
'Machine Learning' 카테고리의 다른 글
고유값, 고유벡터, 고유값 분해 (0) | 2020.08.11 |
---|---|
차원 축소(Dimension Reduction) (0) | 2020.06.17 |
회귀 실습 - (자전거 대여 수요 예측) (0) | 2020.05.28 |
회귀 평가 지표 (0) | 2020.05.27 |
로지스틱 회귀 (2) | 2020.05.27 |