R 중급 ggplot2 New York Taxi cabs 그래프 그리기 [ part 1, 택시 운행 횟수, 운행기간]

  역시  ggplot2는 다른 툴에 비해서 매우 뛰어난 시각화 기능을 가지고 있다.  실제 실무 사례에서도 많이 쓰일 수 있는 데이터 셋과 그래프로 구성 되어 있다.  

글을 쓰고 있는 나도,  예전에 사내 주유소 시스템 만들어서 요일별, 시간 대별 주유 횟수를 그려, 그래프를 개발자에게 그려 달라고 하여,  기능을 사용하였다.  그 때 당시에는 굉장히 신기 했는데, 지금 ggplot2에서는 데이터만 있으면 아주 쉽게 이용 할 수 있다.    


뉴욕 택시 데이터 셋 ggplot2

아래는 UCSanDiego  분석한 뉴욕 택시 자습서(New York Taxi cabs) 그래프 그리는 것이다.  

  이것은  쉽게 설명 하려고,  스크립트 코드를 길고 자세 하게 구성 하였다. 



  

 뉴욕 택시 자습서 

     이 데이터 세트는 2015년 6월에  뉴욕시 노란색 택시 데이터 셋으로,  1,200만회가 넘는 운행 기록을 가지고 있다.  전체 데이터를 사용하지 않으려는 경우 5%의 랜덤 서브 샘플 데이터가 있다.   이번에는 그것을 가지고 사용할 것이며,  개별 택시의 ID가 포함되어 있지 않으므로, 동일한 택시의 운전사의 기록을 살펴 볼 수가 없다. 

 아래는 5%의 샘플 셋을 사용한다. 


# 뉴욕 택시 한글로 표현
  library(tidyverse)
  library(lubridate)
  library(forcats)
  library(scales)
  library(rio)
library(readxl)
library(httr)

# 파일을 불러오는 path를 url 변수로 정의      

url = "https://drive.google.com/u/0/uc?id=1d9Hi0eEvnlheBJsFGiavXxkwdcXzFKyT&export=download"
GET(url, write_disk(tf <- tempfile(fileext = ".xlsx")))
system.time( taxi <- read_excel(tf, 1L))  
##    user  system elapsed 
##   5.449   1.249   6.699
  str(taxi)
## 'data.frame':    616247 obs. of  19 variables:
##  $ VendorID             : num  2 1 2 2 1 2 1 2 2 1 ...
##  $ tpep_pickup_datetime : POSIXct, format: "2015-06-12 12:51:09" "2015-06-25 06:13:56" ...
##  $ tpep_dropoff_datetime: POSIXct, format: "2015-06-12 13:02:49" "2015-06-25 06:36:35" ...
##  $ passenger_count      : num  1 1 5 1 2 1 1 4 5 1 ...
##  $ trip_distance        : num  1.58 5.3 4.47 0.88 3.8 1.35 0.4 0.88 2.36 2.4 ...
##  $ pickup_longitude     : num  -74 -74 -74 -74 -74 ...
##  $ pickup_latitude      : num  40.8 40.8 40.7 40.7 40.7 ...
##  $ RateCodeID           : num  1 1 1 1 1 1 1 1 1 1 ...
##  $ store_and_fwd_flag   : chr  "N" "N" "N" "N" ...
##  $ dropoff_longitude    : num  -74 -73.9 -74 -74 -74 ...
##  $ dropoff_latitude     : num  40.8 40.8 40.8 40.7 40.7 ...
##  $ payment_type         : num  1 1 1 2 2 1 2 1 2 1 ...
##  $ fare_amount          : num  9 20 17.5 7.5 14.5 9.5 3.5 5.5 11 12 ...
##  $ extra                : num  0 0 0 0 0.5 0 0.5 0.5 0 0.5 ...
##  $ mta_tax              : num  0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 ...
##  $ tip_amount           : num  1.96 4.15 2 0 0 0 0 1.36 0 1 ...
##  $ tolls_amount         : num  0 0 0 0 0 0 0 0 0 0 ...
##  $ improvement_surcharge: num  0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 ...
##  $ total_amount         : num  11.8 24.9 20.3 8.3 15.8 ...

 

위의 데이터의 성격을 보면,  택시를 승차한 시각(tpep_pickup_datetime), 택시를 하차한 시각(pep_dropoff_datetime)이 있다. 승객의 수( passenger_count) 거리 ( trip_distance) 그리고, GPS 위치 값으로 해서 승차한 위치가 있고, 가격정보가 있다. 데이터 성격으로 보았을때 누구나 이해하기 쉬운 데이터 셋으로 이루어 졌다.




🚚 데이터 전처리

아래 데이터는 시간 데이터 (요일, 일, 시간) 단위별로 데이터를 나누었고, 운행 기간, 운행 속도, 결제 지불 방식(카드, 현금, 무료, 다른 것)으로 나누었다. 이 정도로 데이터 전처리가 되면, 요일, 일, 시간 단위 별로 배차 할 때 의사 결정 할 수 있는 정보는 다 볼 수 있다.

  taxi <- taxi %>% 
    mutate(weekday = wday(tpep_dropoff_datetime, label = TRUE, abbr = TRUE),
           hour.trip.start = factor(hour(tpep_pickup_datetime)),
           day = factor(mday(tpep_dropoff_datetime)),
           trip.duration = as.numeric(difftime(tpep_dropoff_datetime,tpep_pickup_datetime,
                                              units = "min")),
           trip.speed = ifelse(trip.duration >=1, (trip_distance/60),NA),
           payment_type_label = fct_recode(factor(payment_type),
                                           "Credit Card" = "1",
                                           "Cash" =  "2",
                                           "No Charge" = "3",
                                           "Other" = "4"))

   위 전처리에서 간단하게 기술 적으로 설명 하면 아래와 같다. 

  • wday :  시간 데이터를 일자로 바꾸는것
  • factor :  그래프를 그리기 위해 숫자형 데이터를 범주형으로 바꾸는 것
  • difftime :  택시에서 하차 한 시간과, 승차한 시간을 뺀것
  • as.numeric : 시간 계산 된 것을 숫자형으로 바꾸는 것
  • ifelse :   속도를 구하기 위한 최소 조건을 잡는것 1분 미만이면,  속도를 계산 하지 안흔다. 
  • fct_recode :  지불 방식을 factor (범주) 형태로 데이터 셋을 바꾸는 것 - 그래프를 그리기 위한 목적   

  숫자형은 계산을 위한 목적이고,   범주형은 그래프를 그릴 때 범주 형으로 분류 하는 목적이다. 

이번 파트에서는 택시 운행 횟수와 운행 기간을 다룰 것이다. 




🚚 택시 운행 횟수

일자별 택시 운행 횟수를 그래프로 그린 것이다.
# 택시 운행 회수
  taxi %>% 
    ggplot(aes(x=day)) + geom_bar()

택시 운행 횟수 ggplot2


택시 결제 방법을 현금으로 필터하여 그린 것이다. 

 # 택시 결제 방법
  taxi %>% 
    filter(payment_type_label =='Cash') %>% 
    ggplot(aes(x=day)) + geom_bar()

택시 현금 결재 ggplot2

카드와 현금 지불의 수를 비교하는 그래프이다. 

 # 현금 결재 방법과 카드 결재 방법
  taxi %>% 
    filter(payment_type_label %in% c('Credit Card', 'Cash')) %>% 
    ggplot(aes(x =day, fill = payment_type_label)) +geom_bar()     

일자별 카드와 현금 결재 ggplot2


 신용카드 결재횟수가 현금 결재 횟수 보다 많다,  geom_bar에 'dodge'라는 옵션을 그리면, 막대를 나란히 비교하면서 그릴 수 있다.

 # 카드와 현금 결재와 비교   
  taxi %>% 
    filter(payment_type_label %in%c('Credit Card', 'Cash')) %>% 
    ggplot(aes(x=day, fill = payment_type_label)) + geom_bar(position = 'dodge')

 

일자별  운행 횟수 카드와 현금 결제 비교


시간대별 택시 운행 횟수를 그린 것이다.  자정이후 부터 새벽 5시까지는 점차적으로 운행 횟수가 감소 하고  있고,  운행에 대한 수요는 오후 6시부터 10까지 증가한다.  

택시 시간대별 운행 횟수

택시 시간대별 카드와 현금 결재 비교한 그래프이다.   모든 시간대가 카드 결재가 많다. 

 # 시간대별  카트와 현금 결재 비교
  taxi %>% 
    filter(payment_type_label %in% c('Credit Card', 'Cash')) %>% 
    ggplot(aes(x=hour.trip.start,fill = payment_type_label)) + geom_bar(position = 'dodge')

시간대별 카드와 현금 결재 비교 ggplot2


요일별 여행을 나눈다.    일요일하고, 월요일은 일정 하다가 화요일/수요일 변화가 있고 목/금토는 일정하다. 

 # week day  요일별  평균 운행 횟수
  taxi %>% 
    group_by(day) %>% 
    summarise(n = n(),
              wday = weekday[1]
              ) %>% 
    group_by(wday) %>% 
    summarise(n.trip.mean = mean(n)) %>% 
    ggplot(aes(x = wday, y =n.trip.mean)) +geom_bar(stat = 'identity')
요일별 택시 운행 횟수 ggplot2

 일단위 운행 횟수에 대한 시계열 데이터 형태로 표현 하 수 있다.  여기에서  옵션 group = 1은 단순히 모든 것을 의미 한다. 

# 일 단위 운행 횟수에 대한 시계열 데이터 형태로 표현 할 수 있다. 
  taxi %>% 
    count(day) %>% 
    ggplot(aes(x=day, y=n)) + geom_point() + geom_line(aes(group=1), linetype='dotted')

택시 일단위 운행 횟수 시계열 그래프 ggplot2


시간단위 운행 횟수 시계열 데이터 표현 방법이다.   

 # 시간단위 운행 횟수 시계열 데이터 형태 표현
  taxi %>% 
    count(hour.trip.start) %>% 
    ggplot(aes(x = hour.trip.start, n)) +
    geom_point() +
    geom_line(aes(group=1),linetype='dotted')  

시간대별 택시 운행 횟수 ggplot2


  카드와 현금 결재 색으로 구분해서 시계열 그래프를 그렸다. 위의 막대 그래프 보다는 확실하게 눈에 잘 띈다.  새벽과 아침시간대에는 카드와 현금 비중이 적어 보인다.   

 # 카드와 현금 결재 색 나누기 
  taxi %>% 
    filter(payment_type_label %in% c('Credit Card', 'Cash')) %>% 
    count (payment_type_label, hour.trip.start) %>% 
    ggplot(aes(x=hour.trip.start, y = n, color = payment_type_label, group=payment_type_label))+
    geom_point() +
    geom_line(linetype='dotted')

시간 대별 카드와 현금 결재 추세 ggplot2




🚚 택시 운행기간

택시 운행 기간에 대한 시각화를 할 것이다 운행 기간의 전체 분포가 어떠한가? 히스토그램을 그려 사용할 수 있다. 아래 그래프를 보면, 운행 기간이 많이 큰것 이 있어, 정확한 분포를 볼수가 없다.

# 운행 기간  히스토그램
  taxi %>% 
    ggplot(aes(x=trip.duration)) + geom_histogram()

택시 운행기간 히스토그램 ggplot2

정확한 분포를 볼수 없으면,  운행 기간이 긴 것을 보고,  분포를 정하는데,  2시간 이상 운행하는 비중을 보면 0.9% 정도이다.  

# 운행 기간 긴것 보기 
  taxi %>% 
    arrange(desc(trip.duration)) %>% 
    select(tpep_pickup_datetime,tpep_dropoff_datetime, trip.duration) %>% 
    slice(1:5)
##   tpep_pickup_datetime tpep_dropoff_datetime trip.duration
## 1  2015-06-27 17:42:24   2015-06-30 10:53:08      3910.733
## 2  2015-06-18 22:37:26   2015-06-19 22:37:02      1439.600
## 3  2015-06-07 18:40:43   2015-06-08 18:40:08      1439.417
## 4  2015-06-27 23:47:54   2015-06-28 23:47:16      1439.367
## 5  2015-06-09 21:45:47   2015-06-10 21:45:09      1439.367
# 2시간 이상 운전하는 비중 보기   
  sum(taxi$trip.duration > 120) /nrow(taxi)
## [1] 0.0009330674
#0.9% 이상되는 2시간 이상 운행 하는 데이터를 빼고 히스토그램 그리기 
  taxi %>% 
    ggplot(aes(x=trip.duration)) +geom_histogram() +xlim(0,120)

택시 운행하는 기간 히스토그램  단위 분 ggplot2


일별 운행하는 기간을  시계열 그래프로 본다. 

# 일별 운행하는 기간 중위 값 보기 
  taxi %>% 
    group_by(day) %>% 
    summarise(med.duration = median(trip.duration)) %>% 
    ggplot(aes(x= day, y=med.duration)) +
    geom_point() +
    geom_line(aes(group=1),linetype='dotted')

택시 일별 운행 하는 기간 ggplot2


여기에서 요일을 포인트를 줘서 시각적으로 분석 할 수 있다. 

# 조금더 요일을 시각적으로 강조해서 보자
  taxi %>% 
    group_by(day) %>% 
    summarise(med.duration = median(trip.duration),
              weekday = weekday[1]) %>%  
    ggplot(aes(x =day, y = med.duration, group =1)) +
    geom_point(aes(color = weekday), size = 5) +
    geom_line(linetype = 'dotted')+
    labs( x = 'Day of Month',
               y = 'Median trip Duration (Mins.)',
               titile ='Median Trip Duration by Day of Month')

일별 평균운행 기간 시계열 ggplot2


그래프에 요일 텍스트를 삽입 하여 그래프를 그린다. 

# 그래프에 요일 텍스트를  넣을 수 있다. 
  taxi %>% 
    group_by(day) %>% 
    summarise(med.duration = median(trip.duration),
              weekday = weekday[1]) %>% 
    ggplot(aes(x=day, y= med.duration)) + geom_text(aes(label=weekday)) +
    geom_line(aes(group=1), linetype = 'dotted') +
    labs( x = 'Day of Month',
          y = 'Median Trip Duration (Mins.)',
          title = 'Median Trip Duration by Day of Month')

요일을 텍스트를 나타냄 ggplot2


운행 기간의 중위수를 시간대 별로 계산하여 그래프를 그릴 수 있다. 

운행 기간의 중위수를 시간대별로 계산 ggplot2


이 패턴이 일주일 내내 안정적으로 유지 되는가?  평일마다 관계를 정리 해 보겠다. facet_wrap형태로 데이터를 그리면 요일별로 분리되어 그래프가 그려진다.  이것은 복잡하지만 매우 유익한 것으로  아래의 명령어를 사용하면 쉽게 그릴 수 있다. 

#  요일 별로 중위 수값을 볼수 있다. 
  taxi %>% 
    group_by(weekday, hour.trip.start) %>% 
    summarise(med.duration = median(trip.duration)) %>% 
    ggplot(aes(x = hour.trip.start, y = med.duration, group = weekday, color = weekday))+
    geom_point(size = 3) +
    geom_line(size = 0.5) +
    facet_wrap(~weekday, nrow = 1)+
    theme(legend.position = "none")+
    scale_x_discrete(breaks = c(0, 3, 6, 9, 12, 15, 18, 21 ))

요일 시간대별 시계열 그래프 그리기 ggplot2


 지불 유형에 따라서 2차원 facet을 이용하여 그리드 형태의 그래프를 그릴 수 있다. 

 #facect함수를 이용하여, 그래프를 2개의 요소로 그림을 그릴수 있다. 
  taxi %>% 
    filter(payment_type_label %in% c('Credit Card', 'Cash')) %>% 
    group_by(weekday, hour.trip.start, payment_type_label) %>% 
    summarize(med.duration = median(trip.duration)) %>% 
    ggplot(aes(x = hour.trip.start, y= med.duration, group = weekday, color = weekday)) +
    geom_point(size = 3) +
    geom_line(size = 0.5) +
    facet_grid(weekday~payment_type_label) +
    theme(legend.position = "none")+
    scale_x_discrete(breaks = c(0, 3, 6, 9, 12, 15, 18, 21))

2차원 facet 그래프 ggplot2


요일 별로 facet 를 나누어  결재 유형을 나누어서 요일 시간대별 금액의 패턴을 볼수 있다. 

# 각 요일별로 facet을 나누어서 카드와 현금의 금액의 패턴을 볼 수 있다. 
  taxi %>% 
    filter(payment_type_label %in% c('Credit Card', 'Cash')) %>% 
    group_by(weekday, hour.trip.start, payment_type_label) %>% 
    summarize(med.duration = median(trip.duration)) %>% 
    ggplot(aes(x = hour.trip.start, y= med.duration, group = payment_type_label,
               color = payment_type_label, linetype = payment_type_label, shape = payment_type_label))+
    geom_point(size = 2) +
    geom_line(size = 0.5) +
    facet_wrap(~weekday, nrow = 1) +
    labs(x = 'Time of Day',
         y = 'Median Trip Duration') +
    scale_x_discrete(breaks = c(0,6,12,8))

각 요일별 facet을 나눈 시계열 차트 ggplot2


   ggplot2에  위와 같이 사람 손이나  다른 툴에서는 그릴 수 없는 그래프를 아주 쉽게 그려 낼  수 있다는 것에 놀라울 뿐이다.   

   분석은 모델로 표현 하는 것이 모두라고 생각 하지만,  그래프로 표현하여, 분석 하는 것이 제일 좋다.   최고 의사 결정권자 대부분이 잘 정리된 그래프를 보고 의사 결정을 하지 않는가?


그리고  위의 내용은 아래의 사이트에서 가져온 것이다.

http://lab.rady.ucsd.edu/sawtooth/business_analytics_in_r/Viz1.html

댓글 없음:

댓글 쓰기

css cheat sheet 클래스 선택자, margin(마진), display , center 조정 간단한 구성 요소

 앞에서는 html의 간단한 sheet를 소개 하였습니다.   html은  주로 골격을 나타나는 것이라, 디자인을 하는데는 css로 하여야 합니다.  아래 코드와 같이 css 관련 하여 매우 간단하게 코딩 하겠습니다.  body 부분의 css 코딩  ...