티스토리 뷰
캐글의 자전거 대여 수요(Bike Sharing Demand) 예측 경연에서 사용된 데이터를 이용해 선형 회귀와 트리 기반 회귀를 비교해봅시다.
해당 데이터는 2011년 1월 ~ 2012년 12월까지 날짜/시간, 기온, 습도, 풍속 등의 정보를 기반으로 1시간 간격 동안의 자전거 대여 횟수가 기재돼 있습니다. 데이터 세트의 주요 피처는 다음과 같습니다. 이 중 타겟값은 맨 마지막 피처인 count로 '대여 횟수'를 의미합니다.
Columns 명 | 데이터 내용 |
Datetime | 시간 (YYYY-MM-DD 00:00:00) |
Season | 봄(1) 여름(2) 가을(3) 겨울(4) |
Holiday | 공휴일(1) 그외(0) |
Workingday | 근무일(1) 그외(0) |
Weather | 아주깨끗한날씨(1) 약간의 안개와 구름(2) 약간의 눈,비(3) 아주많은비와 우박(4) |
Temp | 온도(섭씨로 주어짐) |
Atemp | 체감온도(섭씨로 주어짐) |
Humidity | 습도 |
Windspeed | 풍속 |
Casual | 비회원의 자전거 대여량 |
Registered | 회원의 자전거 대여량 |
Count | 총 자전거 대여량 (비회원+회원) |
데이터 세트를 불러오고 대략적인 데이터를 확인해봅시다.
데이터 세트는 10886개의 레코드와 12개의 피처로 구성돼 있습니다. 결손값은 없으며, 대부분의 피처는 int 또는 float 숫자형입니다. 그러나 datetime 피처의 경우 object 형입니다. "년-월-일 시:분:초"를 나타내는 문자열이므로, 모델에 데이터를 투입하기 전에 전처리를 해야합니다.
datetime을 년, 월, 일 그리고 시간과 같이 4개의 속성으로 분리하겠습니다. 판다스에서 이러한 형태의 문자열을 년도, 월, 일, 시간, 분, 초로 편리하게 나누어 변환하려면 먼저 문자열을 'datetime' 타입으로 변경해야 합니다(우연히 해당 데이터 세트의 datetime 피처명과 같을 뿐, 둘이 혼동하면 안됩니다). 문자열을 datetime 타입으로 변환하기 위해선 apply(pd.to_datetime) 메서드를 사용하면 됩니다.
"datetime" 피처를 datetime 타입으로 변환한 뒤, "year", "month", "day", "hour" 피처를 새로 만들어줍시다. 변환된 datetime 피처에 lambda 함수를 하여 각 속성을 떼어오면 됩니다. 시각은 "hour"까지만 기록하는 걸로하고, 이제 "datetime" 피처를 드랍하면 됩니다.
또한 "casual" 피처는 비회원 사용자의 자전거 대여 횟수이고, "registered" 피처는 회원의 자전거 대여 횟수이므로, count = casual + registered입니다. 어차피 count값만 예측하면 되므로, 두 피처는 딱히 필요하지 않습니다. 오히려 상관도가 높아 예측을 저해할 우려가 있기 때문에 드랍하겠습니다.
이번에는 주요 피처 별로 count가 어떻게 분포되어 있는지를 시각화해봅시다. 총 8개의 피처에 대해, 각 피처의 값에 따른 count의 분포를 시각화하기 위해 seaborn 패키지의 barplot을 사용합니다. 여러 그래프를 한 번에 시각화하기 위해 matplotlib의 subplots()을 사용합니다.
먼저 년도 별 count를 보면, 2012년의 총 대여 횟수가 2011년의 총 대여 횟수보다 많습니다. 이는 2012년과 2011년의 관계에 어떠한 특별함이 있다기 보다는 시간이 지날수록 자전거 대여 횟수가 지속적으로 증가한 결과로 보입니다. 월별의 경우 1, 2, 3월이 낮고, 6, 7, 8, 9월이 높습니다. 계절의 경우 봄과 겨울이 낮고, 여름과 가을이 높습니다. 날씨의 경우 눈 또는 비가 오는 경우가 낮고, 맑거나 약간 안개가 있는 경우가 높습니다. 시간의 경우 오전 출근 시간(8시)과 오후 퇴근 시간(17, 18시)가 높습니다. 일일 간의 차이는 크지 않으며 휴일 여부와 주중 여부도 대여량에 큰 영향을 끼치지 않습니다.
캐글에서 요구한 회귀 모델의 성능 평가 지표는 RMSLE(Root Mean Square Log Error)입니다. 즉, 오류값의 로그에 대한 RMSE입니다. 아쉽게도 사이킷런은 RMSLE를 제공하지 않아서, 직접 메서드로 정의해야합니다. RMSLE 뿐만 아니라 MAE, RMSE까지 한번에 계산하는 메서드를 정의했습니다.
RMSLE를 구현할 때 한 가지 주의해야 할 점이 있습니다. 넘파이의 log() 메서드를 이용하거나 사이킷런의 mean_squared_log_error() 메서드를 이용할 수도 있지만, 데이터 값의 크기에 따라 오버플로/언더플로 오류가 발생하기 쉽습니다. 따라서 log1p() 메서드를 이용합니다. 그리고 log1p()로 변환된 값은 다시 넘파이의 expm1() 메서드를 통해 쉽게 원래 스케일로 복원할 수 있습니다.
회귀 모델로 학습을 수행하기 전에 데이터 세트에 대해 먼저 처리해야 할 사항이 있습니다. 타겟값이 정규 분포로 돼 있는지 확인하는 것과 카테고리형 피처를 원-핫 인코딩으로 인코딩하는 것입니다. 일단 아무런 확인도 하지 않을 채 LinearRegression 클래스로 데이터를 학습하고 테스트 데이터에 대해 예측 성능을 평가해봅시다.
RMSE가 약 140로 예측 오류가 비교적 큽니다. 실제값과 예측값이 어느 정도 차이가 나는지 DataFrame 칼럼으로 만들어서 오류 값이 가장 큰 순으로 5개만 확인해봅시다.
가장 큰 상위 5위 오류값은 546~568로 매우 큽니다. 회귀에서 이렇게 큰 예측 오류가 발생할 경우 먼저 타겟값의 분포가 왜곡된 형태인지 확인해야 합니다. 타겟값은 정규분포일 때가 가장 좋습니다.
판다스의 hist() 메서드를 이용해 타겟값의 분포를 확인해봅시다. 정규분포가 아닌, 0 ~ 200 사이에 값이 몰려있는 것을 확인할 수 있습니다. 이렇게 왜곡된 값을 정규 분포 형태로 바꾸는 가장 일반적인 방법은 로그를 적용하는 것입니다. 나중에 모델의 예측값은 다시 expm1() 메서드를 통해 원래 스케일로 원상 복구하면 됩니다.
넘파이의 log1p() 메서드를 적용하여 타겟값을 변환한 후, 분포를 다시 확인합시다. 변환 전보다 훨씬 정규 분포에 가까운 형태로 변환된 것을 확인할 수 있습니다.
타겟값을 로그 변환 한 뒤 학습을 수행합시다. RMSLE 오류는 줄어들었지만, RMSE와 MAE는 오히려 증가했습니다. 이번에는 개별 피처에 인코딩을 적용해보겠습니다. 먼저 각 피처의 회귀 계수값을 시각화해봅시다.
year, hour, month, season, holiday, workingday 피처의 회귀 계수 영향도가 상대적으로 높습니다. 해당 피처들은 숫자값입니다. 하지만 이들 피처의 경우 개별 숫자값의 크기가 의미가 있는 것이 아닙니다. 즉, 모두 카테고리형 피처입니다. 원-핫 인코딩을 통해 변환해야 합니다.
판다스의 get_dummies()를 이용해 이러한 피처들을 모두 원-핫 인코딩합시다.
원-핫 인코딩을 수행한 데이터 세트를 LinearRegression, 릿지, 라쏘 모델로 학습한 후 예측 성능을 확인합시다. 원-핫 인코딩을 적용하고 나서 선형 회귀 모델의 예측 성능이 많이 향상됐습니다.
원-핫 인코딩 된 데이터 세트에서 회귀 계수가 높은 피처를 다시 시각화해봅시다. 원-핫 인코딩으로 피처가 많이 늘어났으므로, 회구 계수 상위 25개 피처를 추출합시다. 원-핫 인코딩 후에는 year_2012, year_2011과 같이 여전히 year 관련 피처들의 회귀 계수 값이 높지만, season이나 weather와 같은 피처들의 회귀 계수 값도 상대적으로 많이 커졌습니다. 원-핫 인코딩을 통해서 피처들의 영향도가 달라졌고, 모델의 성능도 향상되었습니다. 반드시 그런것은 아니지만, 선형 회귀의 경우 중요 카테고리성 피처들은 원-핫 인코딩 변환하는 것이 모델의 성능에 중요한 영향을 끼칠 수 있습니다.
이번에는 회귀 트리를 이용하여 예측을 수행해봅시다. XGBoost의 경우 DataFrame이 학습/테스트 데이터로 입력될 경우 버전에 따라 오류가 발생할 수 있으므로, 학습/테스트 데이터를 DataFrame의 values 속성을 이용해 넘파이 ndarray로 변환하겠습니다.
결과적으로 선형 회귀 모델보다 예측 성능이 향상되었습니다. 하지만 회귀 트리가 선형 회귀보다 반드시 더 나은 성능을 가진다는 의미는 아니며, 데이트 세트의 유형에 따라 결과는 얼마든지 달라질 수 있습니다.
'파이썬 머신러닝 완벽 가이드' 카테고리의 다른 글
파이썬 머신러닝 완벽 가이드 : 차원 축소 개요와 PCA(Principal Component Analysis) (0) | 2023.05.22 |
---|---|
파이썬 머신러닝 완벽 가이드 : 캐글 주택 가격 예측 (고급 회귀 기법) (1) | 2023.05.13 |
파이썬 머신러닝 완벽 가이드 : 로지스틱 회귀와 회귀 트리 (0) | 2023.05.12 |
파이썬 머신러닝 완벽 가이드 : 선형 회귀 모델을 위한 데이터 전처리 (0) | 2023.05.12 |
파이썬 머신러닝 완벽 가이드 : 규제 선형 모델 - 릿지, 라쏘, 엘라스팃넷 (0) | 2023.05.12 |