brunch

You can make anything
by writing

C.S.Lewis

by 이준 Dec 22. 2020

시간과 온도에 따른 자전거 대여 수 예측 변화

ggplot() 그래프 그리기

데이터 분석에 대한 관심이 높아지면서, 입문자를 위한 교육 프로그램이 다양하게 생겼습니다.

마케터에게도 데이터 분석은 이제 남의 이야기가 아니기에... 저도 자연스럽게 이런저런 수업을 들었는데요. 프로그래밍 언어도 결국 언어를 배우는 것이기에 반복하지 않으면 까먹고, 말로 밷지 않으면 의미가 없다는 걸 뼈저리게 느꼈습니다. 


백날 문법책을 읽어봤자 회화가 안되는 것처럼... 그렇게 책을 보고 수업을 들었지만, 막상 시간이 지나자 내용은 희미해지고, 실무 적용은 택도 없더군요. 


수업을 듣던 중 강사님에게 이런 상황을 설명하고 도움을 청하자, 기초 수업이 도움이 되는 단계는 지났고, 캐글 사이트에서 직접 필사도 해보고 코드를 분석해보며 공부하길 추천해주셨습니다. 


솔직히... 캐글의 존재를 알았지만 '그걸 어떻게 해?'라는 생각이 있어 나중에 해봐야지라며 미루곤 했는데요. 근데 이제 슬슬 궁금하기도 하고, 새로운 공부법을 한번 시작해보고 싶어서 시작하게 되었습니다. 


데이터 과학자, 분석가같은 거창한 이름은 아니어도,  마케팅 데이터를 활용할 수 있을 정도는 되면 좋겠다는 생각으로 시작해 보겠습니다. 저도 그저 막 입문을 마친 초급 수준이기에 차근차근 해보도록 하겠습니다.


캐글 데이터 중 유명 데이터 사례인 'Bike Sharing Demand'를 활용해 공부합니다. 타이타닉 생존자 예측만큼 사람들에게 많이 쓰이고 공부하는 데이터인데요. Bike Sharing Demand 데이터는 한 도시의 자전거 공유 시스템 기록 데이터입니다. 

바로 요 데이터.

캐글의 자전거 공유 수요 데이터는 아래 주소에서 받을 수 있습니다.

https://www.kaggle.com/c/bike-sharing-demand/ 

오늘은 시간과 온도에 따른 자전거 대여 변화를 살펴보려고 합니다.

본격적인 시작에 앞서 데이터를 살펴보았습니다. 


기초 데이터 살피기

① 데이터 필드

Data Fields

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 


② 간단한 궁금한 통계를 살펴보았습니다.



install.packages("ggplot2") 

install.packages("psych") 

install.packages("pastecs") 

install.packages("dplyr") 

install.packages("gridExtra") 


library(ggplot2) 

library(psych) 

library(pastecs) 

library(dplyr) 

library(gridExtra) 


train<- read.csv("./data/bike/train.csv", header = T, stringsAsFactors = F) View(train) head(train) summary(train) 

str(train)



그래프를 그려볼 것이기 때문에 ggplot2() 패키지를 설치했고, 그 밖에 psych(), pastecs(), dplyr(), gridExtra()을 설치했습니다. psych()와 pastecs는 stat.desc()를 사용하기 위해, dplyr()은 데이터 추출과 정리를 위해 gridExtra는 그래프 배열을 위해 설치했습니다. 


먼저 train 데이터를 저장하고, head(), summay(), str() 함수를 통해 데이터를 간단히 살펴보았습니다.

각 컬럼 이름과 속성을 대략적으로 예상해 볼 수 있고, 제대로 데이터가 입력된 것을 볼 수 있습니다.

각 컬럼별 대표값을 볼 수 있습니다. 최소값, 최대값, 사분위수, 최대값, 평균 등을 살펴볼 수 있습니다. 단순하게 날씨와 계절은 사계절과 4개의 날씨로 나뉜 것을 알 수 있고, 휴일은 0과 1사이의 값으로 이루어져있으며 온도와 체감온도는 온도가 낮을수록 체감 온도는 더 낮고, 온도가 높을수록 체감온도는 더 높은 것으로 보입니다. 

컬럼 속성은 대부분 수치데이터로 기록되어있습니다. 데이트타임은 문자 속성으로 되어있어, date 타입으로 속성 변경이 필요할 것으로 보입니다.


table(is.na(train$temp)) 

hist.temp <- ggplot(data = train, aes(x=temp)) +   

                   theme(legend.position = "none") +    

                  geom_histogram(aes(y = ..density..), colour = "black", fill = "white") +   

      labs(x = "온도",y="밀도")  hist.atemp <- ggplot(data = train, aes(x=atemp,)) +            theme(legend.position = "none") +    geom_histogram(aes(y = ..density..), colour = "black", fill = "white") +   labs(x = "체감 온도",y="밀도")  hist.humidity <-ggplot(data = train, aes(x=humidity,)) +   theme(legend.position = "none") +    geom_histogram(aes(y = ..density..), colour = "black", fill = "white") +   labs(x = "습도",y="밀도")  hist.windspeed <-ggplot(data = train, aes(x=windspeed,)) +   theme(legend.position = "none") +    geom_histogram(aes(y = ..density..), colour = "black", fill = "white") +   labs(x = "풍속",y="밀도")       


grid.arrange(hist.temp, hist.atemp, hist.humidity,hist.windspeed, nrow=2, ncol=2) 


주요 데이터를 뽑아 데이터 히스토그램을 그려보았습니다. 

온도, 체감온도, 습도, 풍속 데이터의 밀도를 보고 주요 속성을 파악해 보았습니다. 


먼저 혹시 모를 결측치가 있을 수도 있기에, is.na()를 통해 각 데이터의 결측치를 파악했습니다.


전체 데이터 10,886개로 결측치 없이 전부 깨끗한 데이터입니다.

ggplot()을 활용해 데이터의 히스토그램을 그렸습니다.

gplot(data = train, aes(x=temp)+ : data는 train 데이터를 활용하겠으며, x축은 temp(온도)로 두겠다는 의미입니다.

theme(legend.position = "none") +    : 이건 범례를 없애겠다는 뜻입니다. 

geom_histogram(aes(y = ..density..), colour = "black", fill = "white") + 

: geom_histogram을 그리겠으며 y 는 밀도값을 넣겠다는 의미고, 색상을 검정선이고 안은 하얀색으로 채우겠다는 의미입니다.

labs(x = "습도",y="밀도") : x축을 습도로, y축을 "밀도"로 표기합니다. 

위 방식으로 4개의 그래프를 그리고, 하나로 정렬해서 볼 수도 있습니다.

grid.arrange(함께 보고싶은그래프, nrow=2, ncol=2) : 해당 그래프를 2행 2열로 정리해 보겠다는 의미입니다. 

정확히는 아직 알 수 없으나, 온도와 체감 그래프가 정규분포 형태와 유사한 것을 볼 수 있습니다.

대략적으로 데이터를 살펴보았고 이제 본격적으로 시간과 온도에 따른 자전거 대여를 살펴보겠습니다. 


시간과 온도에 따른 자전거 대여 변화

x_axis <- "jitter_times" 

y_axis <- "count" color 

<- "temp_f" cat("Number of training rows", nrow(train), "\n") cat("Number of training rows", nrow(test), "\n") 


head(train)


x축은 시간별 변화, y 축은 대여수, color는 온도의 변화를 나타낼 예정으로 해당 축을 임의로 정의했습니다.

cat() 함수를 사용하면 특정 문자열을 그대로 나타낼 수 있습니다.  


이처럼 문자를 그대로 출력하고, 

nrow()를 활용해 각 데이터의 행 개수를 조회했습니다. 

train 데이터는 10,886개의 데이터로, 

test 데이터는 6,493개의 행으로 이루어진 데이터라는 것을 알 수 있습니다.

head()상위 6개의 데이터 값을 조회할 수 있습니다.


install.packages("ggplot2") 

install.packages("lubridate") 

install.packages("scales") 

library(ggplot2) library(lubridate) library(scales) 

train$hour <- hour(ymd_hms(train$datetime)) 

train$times<-as.POSIXct(strftime(ymd_hms(train$datetime),format = "%H:%M:%S"), format="%H:%M:%S") 


train$jitter_times <-train$times+minutes(round(runif(nrow(train),min=0, max=59))) train$temp_f <- train$temp*9/5+32


시간 데이터 부터 정리해 보도록하겠습니다. 그래프를 그릴 예정으로 마찬가지로 ggplot2 패키지를 설치주고, 이번에는 lubridate() 패키지와 scales() 패키지를 추가로 설치해줘야 합니다.

lubraidate() 패키지는 날짜와 시간 데이터를 쉽게 가공할 수 있도록 도와줍니다.  


train$hour 이런 식으로 적어주면 train 데이터프레임에 hour라는 열이 추가되고 새로운 데이터가 기록됩니다.hour() 함수는 값을 시간으로 반환합니다. 안에 들어간 ymd_hms() 함수는 데이터를 연도, 날짜, 시간, 초를 시간 계산 가능한 형태로 가져옵니다. 그 형태를 hour() 함수가 다시 시간으로 변환합니다. 

만약, 시,분까지만 표현되고 초는 가져오지 않으려면 hm까지만 작성해주면 된다.

시간만 남은 hour() 함수

이처럼 맨 앞 시간만 저장된 것을 확인할 수 있습니다.

마찬가지로 새로 만들어지는 times 열에는 분이 들어가고, strftime() 함수는 날짜 데이터를 원하는 형식으로 출력할 수 있습니다.

위 ymd_hms(train$datetime)의 결과물을 format에 밝힌 순서로 바꿨습니다.

POSIXct는 UNIX epoch(1970년)부터 지금까지의 초를 저장하는 방식으로 as.POSIXct는 해당 값을 그 방식으로 저장해줍니다. 

시간 데이터가 저장된 것을 볼 수 있습니다.

남은 두 변수도 jitter_times와 temp_f에 저장시켜 보겠습니다. 

train$times+minutes(round(runif(nrow(train),min=0, max=59)))

이 코드 수식을 뜯어서 보면, runif() 함수로 난수를 train데이터의 행 개수만큼, 0에서 59사이에 수를 생성하고, round() 함수로 소수자리를 버렸습니다. minutes() 함수로 최종적으로는 분의 형태를 띄게 되었습니다.

시간 데이터와 분 데이터가 합해져 임의의 시간이 완성된 것을 볼 수 있습니다.


train$temp_f <- train$temp*9/5+32

마지막 온도 컬럼에는 섭씨로 기록된 온도를 화씨로 변환해서 넣어줍니다. 

이제 데이터를 활용해 ggplot 그래프를 그려보도록 하겠습니다.

p <- ggplot(train[train$workingday==1,], aes_string(x=x_axis, y=y_axis, color=color)) +   geom_point(position = position_jitter(w=0.0, h=0.4))+   theme_light(base_size = 20)+   xlab("Hour of the day")+   scale_x_datetime(breaks = date_breaks("4 hours"), labels=date_format("%I:%M %p"))+   ylab("Number of tBike Rentals") +   scale_colour_gradientn("Temp(°F)", colours = c("#5e4fa2", "#3288bd", "#66c2a5", "#abdda4", "#e6f598", "#fee08b", "#fdae61", "#f46d43", "#d53e4f", "#9e0142")) +   ggtitle("On workdays, most bikes are rented on warm mornings and evenings\n") +   theme(plot.title=element_text(size=18))


ggplot(train[train$workingday==1,], aes_string(x=x_axis, y=y_axis, color=color))

: train 데이터에서 주말이나 공휴일이 아닌 날짜를 x축에 가져왔습니다. 해당 열은 0과 1로 구분되었기에 1에 해당하는 날들만 가져와서 x축에 활용합니다. x축과 y축은 미리 정의했던 문구를 가져오고, 색상은 color가 온도로 정의되었기에 온도를 색으로 표현할 것입니다. 


geom_point(position = position_jitter(w=0.0, h=0.4))+  theme_light(base_size = 20)+

그래프 표현 방법에 대한 부분입니다. geom_point를 활용하고 부가적인 옵션을 주어 그릴 예정입니다.

외운 다기보다 이런 방식이 있다는 식으로 이해했습니다. 


xlab("Hour of the day") + : x축의 이름을 Hour of the day로 정의했습니다. 그 밑의 y축도 같은 원리입니다.


scale_x_datetime(breaks = date_breaks("4 hours"), labels=date_format("%I:%M %p"))+

: x축 날짜 표현 방식에 대한 옵션입니다. 4시간 간격으로 표여줄 것이며, 보여주는 형식은 오전or오후, 시간, 분입니다. 


scale_colour_gradientn("Temp(°F)", colours = c("#5e4fa2", "#3288bd", "#66c2a5", "#abdda4", "#e6f598", "#fee08b", "#fdae61", "#f46d43", "#d53e4f", "#9e0142")) +

: 색으로 표현하기로 했던 온도의 표현 방식입니다. 그라디에이션 형태로 각종 색상값으로 표현할 예정입니다. 


ggtitle("On workdays, most bikes are rented on warm mornings and evenings\n") + theme(plot.title=element_text(size=18)

: 그래프 타이틀 정의와 사이즈에 대한 옵션입니다. 

이 모든 옵션을 포함해 그린 ggplot 그래프의 모습입니다. 

그래프를 읽어보면, 가장 이용자 수가 많은 시간대는 오전 7~9시 사이에 몰려있는 것을 볼 수 있습니다. 날씨가 더운 날에도 이용자가 많은 것을 볼 수 있으며, 반대로 추운 날씨에는 이용자가 줄어드는 것을 확인할 수 있습니다. 전반적으로 오후 1시와 새벽 이른 시간에는 확실히 이용 자체가 줄어드는 모양새입니다. 


날짜, 시간 패키지를 활용해 데이터를 정제하고, 시간 변화에 따른 그라디에이션 효과를 가진 ggplot 그래프를 그려볼 수 있었습니다.

작품 선택
키워드 선택 0 / 3 0
댓글여부
afliean
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari