#1 탐사 분석
kaggle 에 올라온 문제 중 bike sharing demand (https://www.kaggle.com/c/bike-sharing-demand) 라는 문제를 푸는 과정을 정리해 보았다. 이 문제는 2014년 5월 ~ 2015년 5월까지 약 1년간 출제되었는데 비교적 단순하고 데이터가 잘 정리되어 있어 별도의 데이터 정제 작업이 거의 필요없기 때문에 그런지 많은 팀들이 참여해서 인기를 끌었다.
이 문제에서 사용한 데이터는 어떤 도시에서 제공하는 공공 자전거 대여 서비스에서 2년간 집계한 일자별, 시간별 자전거 대여 횟수와 날씨 관련 정보이다. 문제는 매월 1일 ~ 19일까지의 데이터를 바탕으로 20일 ~ 말일까지의 일별, 시간별 자전거 대여 횟수를 예측하는 것이다. 데이터에 대한 설명은 아래와 같다.
datetime - hourly date + timestamp
season - 1 = spring, 2 = summer, 3 = fall, 4 = winter
holiday - whether the day is considered a holiday
workingday - whether the day is neither a weekend nor holiday
weather - 1: Clear, Few clouds, Partly cloudy, Partly cloudy
2: Mist + Cloudy, Mist + Broken clouds, Mist + Few clouds, Mist
3: Light Snow, Light Rain + Thunderstorm + Scattered clouds, Light Rain + Scattered clouds
4: Heavy Rain + Ice Pallets + Thunderstorm + Mist, Snow + Fog
temp - temperature in Celsius
atemp - "feels like" temperature in Celsius
humidity - relative humidity
windspeed - wind speed
casual - number of non-registered user rentals initiated
registered - number of registered user rentals initiated
count - number of total rentals
모든 kaggle의 문제가 그렇듯 제공되는 데이터는 학습 데이터(train)와 예측 데이터(test)로 나뉜다. test 데이터에는 위 필드 중 'casual', 'registered', 'count' 가 빠져 있는데 예측해야할 대상은 'count' 이다(casual과 registered 값을 더하면 count가 된다). 두 데이터는 각각 아래와 같이 생겼다.
이제 우리는 train 데이터에 있는 시간 및 날짜 관련 정보(datetime, season, holiday, workingday)와 날씨 관련 정보(weather, temp, atemp, humidity, windspeed)를 이용해서 이 정보와 자전거 대여 횟수 간의 관계를 설명할 수 있는 모델을 만든 후 이것을 이용해 test 데이터 상의 날짜/날씨 정보에 의하면 사람들이 자전거를 얼마나 빌릴 것인지 예측해야 한다.
예측 분석을 할 때는 보통 각 데이터간의 상관 관계나 패턴을 찾기 위한 탐사 분석을 해야 한다(만약 자신이 해당 분야에 전문가이고 인과 관계를 충분히 알거나 가설을 세울 수 있는 경우라면 이 단계를 건너띄고 바로 가설 검정을 할 수도 있겠다). 탐사 분석이란게 말은 거창하지만 사실 막연하기도 하고 평소 알고 있는 지식이나 상상력, 직관 등을 최대한 활용해야 하는 단계다. 특히, 적절한 시각화가 중요한 단계이기도 하다.
보통 데이터 분석에 R을 많이 사용하는데 R이 갖고 있는 장점 중 하나가 바로 이런 데이터 시각화 기능이 풍부하고 사용하기 편하다는데 있다. 통계 언어라고 하면 왠지 복잡한 수식이나 숫자만 난무할 것이라 생각할 수 있지만 사실 R은 이렇게 데이터 시각화의 중요성 때문에 가장 그래픽 기능이 풍부한 프로그래밍 언어 중 하나이다.
암튼 우선 탐사 분석을 할 때 대개 가장 처음에 하는 것이 scatter plot을 그려보는 것이다. 어떤 이들은 평균이나 표준편차 같은 것을 먼저 살펴보기도 하고 좀 더 통계에 익숙한 사람들은 각 변수간의 상관계수를 뽑아 보기도 한다. 그러나 이런 수치들은 자칫 불필요한 선입관을 주는 위험한 숫자들이다. 내 생각에 탐사 분석의 가장 처음에는 데이터를 최대한 날 것 그대로 봐야 하며 이를 위해선 scatter plot 이 가장 좋다.
train 데이터의 전체 레코드 수는 10,886개인데 이 데이터를 다 plot에 찍어 보기엔 다소 많기 때문에 1000개만 샘플링해서 찍어보면 아래와 같다.
train<-read.csv('train.csv',>
train.sample<-train[sample(1:nrow(train), 1000), ]
plot(train.sample)
얼핏 봐선 뭐가 뭔지 잘 모를 수 있지만 기존 상식과 직관을 조금만 활용해서 데이터를 보면 이 scatter plot에는 제법 많은 정보를 갖고 있다. 내가 이 자료에서 얻은 정보는 아래와 같다. 그림에서 각각의 세부 plot을 참조할 때 (row number, col number)로 표현하겠다.
(6,7)을 보면 temp(실제 온도)와 atemp(체감 온도)는 1에 가까운 양의 상관성이 있다. 그리고 이건 상식적으로 봤을 때 당연하다.
(1, 6)과 (1,7)을 보면 datetime과 온도 사이에는 밀접한 관련이 있다. 이것 역시 당연한 상식이다.
(11, 12)을 보면 registered와 count 간에도 매우 밀접한 양의 상관이 있다. 그런데 자세히 보면 약하게 나마 두 개의 그룹으로 나뉘는 것을 볼 수 있다.
(10, 11)과 (10, 12)를 보면 casual과 registered, count 간에도 상관성이 있는데 registered에 비해 좀 더 명확하게 두 개의 집단이 갈라지는 형태를 볼 수 있다.
(1, 10), (1, 11), (1, 12)를 보면 datetime과 casual, registered, count 간에도 어떤 패턴이 있는 것 같다.
(6, 10) ~ (6, 12), (7, 10) ~ (7, 12)를 보면 temp/atemp와 casual, registered, count 간에도 뭔가 패턴이 있을 것 같다.
그 외에도 눈썰미가 있는 사람이라면 더 많은 정보를 찾을 수 있을 것이다. 어떤 사람들은 위에 내가 적은 내용이 지나치게 작위적이라고 생각할 수 있다. 하지만 현재 단계에서는 다소 억지스럽더라도 최대한 다양한 가설을 세워 보는 것이 좋다고 생각한다. 어차피 이에 대한 검증은 앞으로 하나씩 해나가면 된다. 탐사 분석의 가장 큰 목적은 가설을 세우기 위함인데, 가설은 객관적인 사실 보다는 주관적이고 직관적인 주장에 더 가깝다.
따라서 탐사 분석에서는 지나친 엄밀성을 추구해선 안된다. 앞서 얘기했듯이 오히려 상상력과 호기심이 훨씬 많이 필요한 단계이며 최대한 많은 가설을 뽑아내는 것이 더 중요하다. 지레 겁먹고 확실한 증거만 찾으려다가 한발자국도 나갈 수 없는 것 보다 낫다.
참고로 내가 위 그림에서 어떤 패턴이 있는 것 같다고 판단한 기준은 그림이 '원형에 가까운가 그렇지 않은가' 이다. 위 그림에서 가령 (6, 8)이나 (6, 9)는 원형에 가까운 모양이지만 (6, 10)은 윗부분이 넓게 퍼져있고 밑으로 갈수록 왼쪽 하단으로 좁아지는 형태로 데이터가 분포되어 있는데 이런 경우엔 두 변수간에 어떤 관계가 있을 가능성이 높다. 가장 명확한 패턴을 보이는 것은 선형 모양이다. 가령 (6, 1), (6, 7), (11, 12) 가 그렇다.
이제 좀 더 세부적인 탐사 분석에 들어가 보자.
사실 이 문제를 처음 접했을 때 난 시간이 가장 중요한 설명 변수가 될 것이라고 직감했다. 사람들이 아무래도 새벽시간보다는 낮시간에 자전거를 더 많이 탈 것이기 때문이다. 그리고 실제로 scatter plot을 보면 날짜 관련 필드가 자전거 대여 횟수와 관련성이 높아 보인다. 온도 역시 관련성이 높아 보이는데 실제 영향을 많이 줄 수도 있지만 생각해 보면 온도 역시 날짜(계절) 및 시간과 관련성이 매우 높기 때문에 그렇게 보이는 것일 수 있다.
따라서 이러한 날짜/시간 요소와의 관련성을 좀 더 자세히 보기 위해 datetime 필드를 년, 월, 일, 시로 분리하였고 추가로 요일 정보까지 추출하였다.
data$year<-as.integer(substr(data$datetime, 1, 4))
data$month<-as.integer(substr(data$datetime, 6, 7))
data$hour<-as.integer(substr(data$datetime, 12, 13))
data$day<-as.integer(substr(data$datetime, 9, 10))
data$weekday<-as.integer(format(as.POSIXct(data$datetime, format='%Y-%m-%d %H:%M'), format='%u'))
이제 실제로 시간 정보가 자전거 대여 횟수와 관련성이 높은지 확인을 위해 전체 데이터에 대해서 시간대별 자전거 대여 횟수에 대한 boxplot을 그려보았다.
require(ggplot2)
ggplot(train, aes(x=as.factor(hour),>
예상대로 시간대별 대여 횟수에 큰 차이가 있는 것을 볼 수 있다. 새벽 3~4시가 가장 대여횟수가 적고 오전 8시까지 증가했다가 다시 낮시간에는 감소하고 다시 17시 경에 증가한 후 서서히 감소하는 패턴을 보인다. 대여 횟수가 높은 시간대를 보면 출퇴근 시간대에 가까운 것을 알 수 있다. 그렇다면 아마 사람들이 출퇴근시에 자전거를 빌려서 이동하는 것일 수 있다. 이 가설이 타장한지 확인해 보려면 근무일 여부에 따라 시간대별 자전거 대여 회수를 확인해 보면 된다. 아래 코드는 workingday(0은 휴일, 1은 근무일) 값에 따른 시간대별 자전거 대여 횟수를 boxplot으로 표시해준다.
ggplot(train, aes(x=as.factor(hour),>
역시 예상대로 근무일(오른쪽)에는 출퇴근 시간대에 자전거 대여 횟수가 높은 것을 볼 수 있지만 휴일(왼쪽)에는 낮시간에 대여 횟수가 더 많다. 따라서 이를 통해 자전거 대여 횟수를 예측할 때는 시간대 정보 뿐만 아니라 근무일 여부가 중요한 정보가 된다는 것을 덤으로 알 수 있다.
또한 한 가지 흥미로운 점은 casual과 registered에 영향을 주는 변수 및 패턴이 매우 다르다는 것이다. 가령 시간대별 대여 횟수 및 월별 대여 횟수에 대해서 casual과 registered의 패턴은 아래와 같이 큰 차이를 보인다.
ggplot(train, aes(x=as.factor(hour),>ggplot(train, aes(x=as.factor(hour),>
ggplot(train, aes(x=as.factor(month),>ggplot(train, aes(x=as.factor(month),>
때문에 대여 횟수를 예측할 때 count에 대해서 한 가지 예측 모델을 생성하는 것보다 casual과 registered에 대해서 별도의 예측 모델을 만든 후 각각에 대한 예측값을 더해서 count를 만드는 것이 더 좋은 결과가 나올 것이라고 짐작할 수 있다.
이런 식으로 시각화를 이용해서 다양한 변수 간의 관계에 대해서 탐사 분석을 수행할 수 있으며 이를 통해 다음 단계에서 진행할 예측 모델링 시 어떻게 모델을 만드는 것이 좋을지에 대한 대략적인 방향을 잡을 수 있다