소품집

[Kaggle] Japan Restaurant Visitor Forecasting EDA with R 본문

AI

[Kaggle] Japan Restaurant Visitor Forecasting EDA with R

sodayeong 2020. 9. 10. 23:48

정말,,, 역대급으로 오래 걸리고 있는 kaggle이다.

잔 기술 많이 배워서 꼼꼼하게 하고 있습니다 😎

 

 

 

 

 

getwd()
setwd('/Users/dayeong/Desktop/reserch/data')

# Restaurant Visitor Forecasting EDA with R
# https://www.kaggle.com/maestroyi/restaurant-visitor-forecasting-eda-with-r

# general visualisation
library(ggplot2)
library(scales)
library(grid)
library(gridExtra)
library(RColorBrewer)
library(corrplot)

# general data manipulation
library(dplyr)   # data manipulation
library(readr)   # input/output
library(data.table) #data manipulation
library(tibble)  # data wrangling
library(tidyr)   # data wrangling
library(stringr) # string manipulation
library(forcats) # factor manipulation

# specific visualisation
library(ggrepel)
library(ggridges)
library(ggExtra)
library(ggforce)
library(viridis)

# speific data manipulation
library(lazyeval) # data wrangling
library(broom)    # data wrangling
library(purrr)    # string manipulation

# Date plus forecast
library(lubridate) # date and time
library(timeDate)  # date and time
library(tseries)   # time series analysis
library(forecast)  # time series analysis
library(prophet)   # time series analysis
library(timetk)    # time series analysis

# Maps / geospatial
library(geosphere)  # geospatial locations
library(leaflet)    # maps
library(leaflet.extras) # maps
library(maps)  # maps


# 2. Preaprations
# Data loading
air_visits <- read.csv("air_visit_data.csv")
air_reserve <- read.csv('air_reserve.csv')
hpg_reserve <- read.csv('hpg_reserve.csv')
store_ids <- read.csv('store_id_relation.csv')
test <- read.csv('sample_submission.csv')
holidays <- read.csv('date_info.csv')

# 3. Overview : file structure and content
# summary info check.
summary(air_visits) # air restauranst 과고거방문 data. main training data set임.
summary(air_reserve) # air & hpg 레스토랑 예약 시스템
summary(hpg_reserve) # air & hpg 레스토랑 세부 정보 
summary(store_ids) # air & hpd id

air_visits %>% 
  distinct(air_store_id) %>% nrow() # 829개의 데이터가 있는 것으로 보아 data set의 크기가 작다.

# 4. individual feature visualisation 
# 세부분석을 위한 결합 전 개별 data file의 feature 분포를 확인하자. 

# 4.1 Air visits
View(air_visits)

p1 <- air_visits %>% 
  group_by(visit_date) %>% 
  summarise(all_visitors = sum(visitors)) %>% 
  ggplot(aes(visit_date, all_visitors)) +
  geom_line(col = 'blue') +
  labs(y = 'All Visitor', x = 'Date')

p2 <- air_visits %>% 
  ggplot(aes(visitors)) +
  geom_vline(xintercept = 20, color = 'orange') +
  geom_histogram(fill = 'blue', bins = 30) +
  scale_x_log10()

p3 <- air_visits %>%
  mutate(wday = lubridate::wday(visit_date, label = TRUE)) %>%
  group_by(wday) %>%
  summarise(visits = median(visitors)) %>%
  ggplot(aes(wday, visits, fill = wday)) +
  geom_col() +
  theme(legend.position = "none", axis.text.x  = element_text(angle=45, hjust=1, vjust=0.9)) +
  labs(x = "Day of the week", y = "Median visitors")

p4 <- air_visits %>% 
  mutate(month = month(visit_date, label = TRUE)) %>% 
  group_by(month) %>% 
  summarise(visits = median(visitors)) %>% 
  ggplot(aes(month, visits, fill = month)) +
  geom_col() +
  theme(legend.position = 'none') +
  labs(x = "Month", y = "Median visitors")

layout <- matrix(c(1,1,1,1,2,3,4,4),2,4,byrow = TRUE)
multiplot(p1, p2, p3, p4, layout = layout)

# 결과
# - Time serise 상에서 흥미로운 장기 흐름의 구조가 있는 것으로 보인다. 이 것은 신규 레스토랑이 데이터 베이스에 추가된 것과 연관이 있어 보임//
# 게다가 주별 흐름에 연동된 기간 패턴을 볼 수 있었음.
# - 2번째 플랏에서 매장별 일별 방문수가 20명인 곳이 가장 많은 것으로 보임. 드문 경우지만 일 방문 고객수가 100명이 넘는 곳도 간약간 있음
# -> 평균을 기준으로 정규분포를 이룰고 있는 것으로 확인됨. 
# - 우리의 예상(?)대로 금~일요일의 방문자수가 증가하는 것을 볼 수 있다. 
# - 연 기준 차트를 보면 특정 변동이 보임. 12월이 가장 인기 있는 달!

# 2017년 4월 마지막주 ~ 5월까지의 예측을 위해 2016년 training data를 살펴보자.
air_visits %>% 
  filter(visit_date > ymd('2016-04-15') & visit_date < ymd('2016-06-15')) %>% 
  group_by(visit_date) %>% 
  summarise(all_visitors = sum(visitors)) %>% 
  ggplot(aes(visit_date, all_visitors)) +
  geom_line() + 
  geom_smooth(method = 'loess', color = 'blue', span = 1/7) +
  labs(y = "All visitors", x = "Date")

# 4.2 Air Resevations
# 예약 데이터와 실제 방문한 고객의 수를 비교해보자.
# 방문 시간대 차트와 예약후 방문 시간까지의 시간 차트를 나란히 놓고, 시각화 해보자.
foo <- air_reserve %>% 
  mutate(reserve_date = date(reserve_datetime),
         reserve_hour = hour(reserve_datetime),
         reserve_wday = wday(reserve_datetime, label = TRUE),
         
         visit_date = date(visit_datetime),
         visit_hour = hour(visit_datetime),
         visit_wday = wday(visit_datetime, label = TRUE)) 

p1 <- foo %>%
  group_by(visit_date) %>%
  summarise(all_visitors = sum(reserve_visitors)) %>%
  ggplot(aes(visit_date, all_visitors)) +
  geom_line() +
  labs(x = "'air' visit date")

p2 <- foo %>%
  group_by(visit_hour) %>%
  summarise(all_visitors = sum(reserve_visitors)) %>%
  ggplot(aes(visit_hour, all_visitors)) +
  geom_col(fill='blue')

layout <- matrix(c(1,1,2,3),2,2, byrow=T)
multiplot(p1, p2, layout = layout)

# 결과 
# - 2016년의 예약은 많이 저조해보이고, 심지어 예약이 없는 구간도 보인다. 
# - 2016년 연말 기간에 예약이 늘었다. 2017년에 들어서는 급격하게 방문자수가 증가함. 
# - 1분기 이후에는 인위적인 감소는 training time이 끝나는 시기의 이런 예약과 연관이 되어 있어 보인다. 
# - 일반적으로 저녁식사를 하기 위해 직전에 예약이 이루어짐
# - 예약 후 방문까지의 시간은 24시간 주기를 보인다. 방문 몇 시간 전 예약하는 경우가 가장 많지만, 예약이 불가능하면 가능한 다른 날을 예약하는걸로 보인다. 이 차트는 더 긴 시간의 패턴을 보이기 위해 끝이 잘린다. 
# - 예약 후 방문까지의 시간이 긴 것은 예외적인게 아니다. 가장 긴 시간은 1년이 넘는 시간이 있다.

foo %>%
  arrange(desc(diff_day)) %>%
  select(reserve_datetime, visit_datetime, diff_day, air_store_id) %>%
  head(5)
# 가장 긴 시간을 정렬해보면 top5에 단지 두 식당만 있음. -> 핫플이거나 입력의 오류ㄱ일 경우라 생각됨/ 


# 4.3 HPG Reservation 
# 위와 동일하게 예약 data와 실제 고객의 수를 비교해보자.
foo <- hpg_reserve %>%
  mutate(reserve_date = date(reserve_datetime),
         reserve_hour = hour(reserve_datetime),
         
         visit_date = date(visit_datetime),
         visite_hour = hour(visit_datetime))

p1 <- foo %>%
  group_by(visit_date) %>%
  summarise(all_visitors = sum(reserve_visitors)) %>%
  ggplot(aes(visit_date, all_visitors)) +
  geom_line() +
  labs(x="'hpg' visite date ")

p2 <- foo %>%
  group_by(visite_hour) %>%
  summarise(all_visitors = sum(reserve_visitors)) %>%
  ggplot(aes(visite_hour, all_visitors)) +
  geom_col(fill='red')

multiplot(p1,p2)

# 결과 
# - 예약방문 고객은 2016년 12월에 많아지는 패턴을 보이며, 위의 'air' data와 같이 time frame이 끄트머리는 수치 가 떨어짐.
# - 방문시간은 위와 동일하게 저녁대가 가장 많지만, 예약 후 방문까지의 시간은 또 다른 24시간의 패턴을 볼 수 있다.
# - 몇 시간 전의 예약이 하루나 이틀전의 예약보다 특출나게 많지 않다. 
# >> 'air' data와는 완연한 대조를 보여준다. 

# 4.4 Air Store 
# 시각적인 측면을 시각화하고, 공간적 측면도 보자. 

# 지도 mapping
leaflet(air_store) %>%
addTiles() %>% 
  addProviderTiles('CartoDB.Positron') %>% 
  addMarkers(~longitude, ~latitude, popup= ~air_store_id, label = ~air_genre_name,
             clusterOptions = markerClusterOptions())

# 여러 식당 타입 분포와 가장 많은 레스토랑이 있는 곳을 차트로 나타내보자. 
p1 <- air_store %>%
  group_by(air_genre_name) %>%
  count() %>%
  ggplot(aes(reorder(air_genre_name, n, FUN = min), n, fill= air_genre_name)) +
  geom_col() +
  coord_flip() +
  theme(legend.position = 'none') +
  labs(x= 'Type of cuisine (air_genre_name)', y='Number of air restauransts')


p2 <- air_store %>%
  group_by(air_area_name) %>%
  count() %>%
  ggplot(aes(reorder(air_area_name, n, FUN = mean),n, fill = air_area_name)) +
  geom_col() +
  theme(legend.position = 'none') +
  coord_flip()+
  labs(x='Top 15 area (air_area_name)', y='Number of air restaurants')

layout <- matrix(c(1,2), 2,1,byrow = T)
multiplot(p1, p2, layout = layout)

# 시각화 결과, 
# - 이자카야 타입이 가장 많고, 다음은 카페이다. 
# 'Karoke'와 'interanational' , 'Aisan' 타입이 식당은 적어 보인다.
# - 후쿠오카는 면적당 air restauransts가 가장 많다. 그 뒤를 이어 tokyo 지역이 따른다. 

# 4.5 HPG Store
# 위의 air store와 같이 인터랙티브 지도를 만들어보자.
leaflet(hpg_store) %>%
addTiles() %>% 
  addProviderTiles("CartoDB.Positron") %>% 
  addMarkers(~longitude, ~latitude, popup = ~hpg_store_id, label = ~hpg_genre_name,
             clusterOptions = markerClusterOptions())

# hpg restaurants의 지역과 genre를 나타내보자. 
p1 <- hpg_store %>%
  group_by(hpg_area_name, n, FUN = min), n, fill=hpg_genre_name)) +
  geom_col() +
  coord_flip() +
  theme(legend.position = 'none') + 

hpg_store %>% subset(sub_str(hpg_area_name))

str_sub(hpg_store$hpg_area_name,1,20)

p2 <- hpg_store %>%
  mutate(area = str_sub(hpg_area_name,1,20)) %>%
  group_by(area) %>%
  count() %>%
  ungroup() %>%
  top_n(15, n) %>%
  ggplot(aes(reorder(area, n, FUN = min), n, fill=area)) +
  geom_col() +
  theme(legend.position = 'none') +
  coord_flip() +
  labs(x='Top 15 area (hpg_area_name)', y= 'Number of hpg restaurants')

layout <- matrix(c(1,2), 1,2, byrow=T)
multiplot(p1, p2, layout = layout)

# 결과
# - hpg 설명에는 'air' data 보다 많은 gnere 분류가 있다. 
# - 'air' data 에선 세분화된 많은 분류들이 여기선 'japaness style'에 포함된 것 처럼 보임.
# - Top15에는 도쿄와 오사카가 많이 있음ㅇ르 알 수 있음. 

# 4.6 Holidays
# 2017년 예측 기간 data와 2016년의 동일 기간 data의 분포를 나타내는 차트와 드 해를 합한 차트를 보자. 
foo <- holidays %>%
  mutate(wday = wday(calendar_date))

p1 <- foo %>%
  ggplot(aes(holiday_flg, fill = holiday_flg)) +
  geom_bar() + 
  theme(legend.position = 'none')

p2 <- foo %>%
  filter(calendar_date > ymd('2016-04-15')& calendar_date < ymd('2016-06-01')) %>%
  ggplot(aes(calendar_date, holiday_flg, color = holiday_flg)) +
  geom_point(size=2) +
  theme(legend.position = 'none') +
  labs(x='2016 date')
  
p3 <- foo %>% 
  filter(calendar_date > ymd('2017-04-15') & calendar_date < ymd('2017-06-01')) %>% 
  ggplot(aes(calendar_date, holiday_flg, color = holiday_flg)) +
  geom_point(size = 2) +
  theme(legend.position = 'none') +
  labs(x = '2017 date')

layout <- matrix(c(1,1,2,3),2,2,byrow=FALSE)
multiplot(p1, p2, p3, layout = layout)

# 결과 
# - 2016년 4월과 5월은 2017년과 휴일이 같다. 
# - data에서 휴일의 비율은 대략 7%
# 제공된 excel 파일과 kaggle notebook과 변수명 대류가 있는 듯 ...!

# 4.7 Tesst dats set

# train & test data set의 기간 범위를 나타내보자. 
foo <- air_visits %>%
  rename(date=visit_date) %>%
  distinct(date) %>%
  mutate(dest = 'train')
 
bar <- test %>%
  separate(id, c('foo', 'bar','date'), sep='_') %>%
  mutate(date = ymd(date)) %>%
  distinct(date) %>%
  mutate(dest = 'test')

foo <- foo %>%
  mutate(year=year(date)) 

year(foo$date) <- 2017

## 코드 오류남 ㅠㅠ 오ㅔ요 ?? ;;; 
foo %>%
  filter(!is.na(as.data.frame(date))) %>%
  mutate(year=fct_relevel(as.factoryear), c('2017', '2016'))) %>%
  ggplot(aes(date, year, color=dest)) +
  geom_point(shape='|', size=10) +
  scale_x_date(date_labels = '%B', date_breaks = '1 month')


# 5. feature relations 
# 개별 data set을 모두 확인해봤고, 이제 결합해야할 단계.
# 여러 특징들의 관계와 이런 특징이 방문객 수에 어떤 영향을 주는지 찾아보자. 
# 어떤 신호든지 개별 feature 분포의 맥락 안에서 해석해야 한다. 

# 5.1 Visitors per genre
# multi-feature space의첫 번째 차트는 'air_genre_name'에 따라 분류된 air restaurnats의 평균 방문객수를 나타냄/
# facet plot을 써서 14개의 카테고리의 time serise를 나타내보자. 

foo <- air_visits %>%
  left_join(air_store, by = 'air_store_id')

a <- foo %>%
  group_by(visit_date, air_genre_name) %>%
  summarise(mean_visitors = mean(visitors)) %>%
  ungroup()

  ggplot(data=a,aes(visit_date, mean_visitors, color=air_genre_name)) +
  geom_line() +
  labs(y="Average number of visitors to 'air' restaurants", x= 'Date') +
  theme(legend.position = 'none') +
  scale_y_log10() +
  facet_wrap(~air_genre_name)

# 결과
# - 일별 평균 방문객은 10~100명 사이에 분포.
# - 각 카테고리내에서 장기 추세는 안정적으로 보인다. 
# 'Creative Cuisine', 'Okonomiyaki'이외에도 2016년 후반부터 아시안 식당의 인기가 감소하는 추세.
# 모든 curves에서 익숙한 추이가 보인다. 장르별, 요일별 평균 방문객을 좀 세부적으로 보자.
# 'ggridges'패키지로 ridgeline plot을 추가하자. 'Ridgeline plot'은 밀도를 빠르게 비교할 수 있고, 
#장르별 일 방문자의 분포를 나타내는 차트를 그리고, y축은 하나만 나타내되 두 차트 모두에서 공유한다.
  
p1 <- foo %>%
  mutate(wday=wday(visit_date, label = T)) %>%
  group_by(wday, air_genre_name) %>%
  summarise(mean_visitors = mean(visitors)) 
  
p1 <- ggplot(data= p1, aes(air_genre_name, mean_visitors, color=wday)) +
  geom_point(size=4) +
  theme(legend.position = 'left', axis.text.y = element_blank(), 
        plot.title = element_text(size=14)) +
  coord_flip() +
  labs(x="") +
  scale_x_discrete(position = 'top') +
  ggtitle('air_genre_name') +
  scale_color_hue()
  
p2 <- foo %>%
  ggplot(aes(visitors, air_genre_name, fill =air_genre_name)) +
  geom_density_ridges(bandwidth=0.1) + 
  scale_x_log10() +
  theme(legend.position = 'none') +
  labs(x='') +
  scale_fill_cyclical(values=c('blue','red'))

layout <- matrix(c(1,1,2,2,2),1,5, byrow = T)
multiplot(p1,p2, layout=layout)


# 5.2 The impact of holidays
# 휴일인 날과 그렇지 않은 날의 통계를 비교하여 휴일이 방문객 수에 영향을 미치는지 알아보자.

foo <- air_visits %>%
  mutate(calendar_date = as.character(visit_date)) %>%
  left_join(holidays, by ='calendar_date') # calendar_dated을 기준으로 join 

p1 <- foo %>% 
  ggplot(aes(holiday_flg, visitors, color=holiday_flg)) +
  geom_boxplot() +
  scale_y_log10() +
  theme(legend.position='none')

p2 <- foo %>%
  mutate(wday=wday(visit_date, label=T)) %>%
  group_by(wday, holiday_flg) %>%
  summarise(mean_visitors=mean(visitors)) %>%
  ggplot(aes(wday, mean_visitors, color=holiday_flg)) +
  geom_point(size=4) +
  theme(legend.position = 'none') +
  labs(y='Average number of visitors')

layout <- matrix(c(1,2),1,2, byrow = T)
multiplot(p1, p2, layout = layout)

# 결과 
# - 왼쪽 차트를 보면(나는 어떤 이유 때문인지.. 라벨링이 안되어 있음.) 휴일 ㅁ유무에 따른 방문객 수는 큰 차이가 없어보인다. 쑴겨진 세부 정보가 있음!
# - 오르쪽 차트를 보면 휴일이 주말인 경우, 방문객 수에 큰 영향을 미치지 않고 감소한 경우가 있음.
# 하지만 휴일이 주중인 경우는 큰 영향을 미치는 걸로 보임. 특히 월요일과 화요일!!


# 5.3 Restaurants per area and the effect on visitor numbers

# 만약 식당이 유명하거나, 그 지역에 동일한 타입의 식당이 하나뿐이라면 많은 고객을 예상할 수 있을 것 같다. 
# 거리에 동일 타입 내 12개의 다른 식당이 있다면 사람들은 여러 곳으로 갈 것이다. 경제 학자들이 말하는 수요 & 공급의 법칙이다. 
# 그러나 데이터 세싱 같은 snapshot이거나 지역화 특성이 된 곳의 식당은 여전히 경쟁력이 있음.
# 그래서 지역별 특정 장르의 식당 수와 그것들이 방문객 수에 미치는 영향을 알아보자!

air_store %>%
  mutate(area = str_sub(air_area_name,1,12)) %>%
  ggplot(aes(area, air_genre_name)) +
  geom_count(color='blue') +
  theme(legend.position = 'bottom', axis.text.x=element_text(angl=90, hjust = 1, vjust = 0.9))

# 결과
# - 몇 몇 지역에는 많고 다양한 레스토랑이 있지만, 어떤 지역엔 하나의 레스토랑만 있다. (파라미터의 대부분은 비어있음)
# - 유사하게, ‘Izakaya’, ‘Cafe’와 같은 식당은 어디는 흔하지만, 어디는 그렇지 않다. ’Hokkaido Sapporo-shi Minami 3 Jonishi’에는 ’Karaoke bar’가 2군데 뿐이다. ’Tokyo-to Shibuya-ku Shibuya’에서는 ’International’, ‘Asian’ 레스토랑이 2군데씩 뿐이다.

# hpg도 시각화로 나타내보자 
hpg_store %>%
  mutate(area = str_sub(hpg_area_name,1,10)) %>%
  ggplot(aes(area, hpg_genre_name)) +
  geom_count(color='red') +
  theme(legend.position = 'bottom', axis.text.x = element_text(angle=90, hjust=1, vjust = 0.9))
# 결과 
# - hpg역시 air와 동일하게 분포가 높은 곳과 낮은 곳이 있음. 당연히, 도쿄는 다양한 장르가 있음!
# - ‘Japanese style’과 ’Intenational’ 식당은 대부분의 곳에서 인기가 있다. 
# ‘Shanghai food’ or ‘Dimsum’과 같이 ’Amusement bars’, ‘Udon/Soba’ 식당은 희귀하다.


air_store %>%
  group_by(air_genre_name, air_area_name) %>%
  count() %>%
  ggplot(aes(reorder(air_genre_name, n, FUN = mean), n)) +
  geom_boxplot() +
  geom_jitter(color='blue') +
  scale_y_log10() +
  coord_flip() +
  labs(x='Air genre', y='Occurences per air area')

# 결과 
# - 단지 몇 몇 장르만이 지역당 2개 이상의 레스토랑 중위값을 갖고있음. 
# -대다수 장르의 분포는 지역당 2개의 정도의 클러스터에 밀집되어 있고, 'cafes'는 한 지역에 26개의 많은 가게가 있다. 

air_store %>%
  filter(air_store_id == 'air_b5598d12d1b84890' | air_store_id =='air_bbe1c1a47e09f161')

air_visits %>% 
  filter(air_store_id == "air_b5598d12d1b84890" | air_store_id == "air_bbe1c1a47e09f161") %>% 
  arrange(visit_date) %>% 
  head(10)

# hpg도 확인해보자 
foobar <- hpg_store %>%
  group_by(hpg_genre_name, hpg_area_name) %>%
  count()

foobar %>%
  ggplot(aes(reorder(hpg_genre_name, n, FUN = mean), n)) +
  geom_boxplot() +
  geom_jitter(color='red') +
  scale_y_log10() +
  coord_flip() +
  labs(x='hpg genre', y= 'Cases per hpg area')

# 결과
# - 지역당 최소 하나의 장르를 가지고 있고, 전반적으로 'air' 대비 수치가 높아서 중위값이 더 다양함/
# - 흥미로운 장르는 'japaness style'로 이건 중위값이 지역당 10개 이상이다. 
# -이와 반대로 지역당 최소 1개도 되지 않은 낮은 박스 힌지가 여러 장르에 있다. 


# 각 영역의 장르 수에 대한 정보를 바탕으로 떼이터 집합의 클러스터링 또는 '복잡성'를 정량화하고
# 이걸 고객 수와 연관시킬 수 있다. 다음 플롯은 마지막 두 플롯(지역당 동일 장르의 사례)의 'air' 및 'hpg 데이터 포인트의 전체 분포를 보여준다. 

# 더해서, 각 클러스터링 사례의 평균 고객 수를 추정. 
# 이를 위해 먼저 지역 장르의 log1p로 변환된 고객 수의 평균을 구하고, 각 경우(한 지역에 동일한 장르의 발생수)에 대해
# 평균 및 표준편차를 계산할 것이다. 이건 방문객 수 분포를 보다 평범하게 만들기 위한 것!

foo <- air_visits %>%
  left_join(air_store, by = 'air_store_id') 

bar <- air_store %>%
  group_by(air_genre_name, air_area_name) %>%
  count()

foobar <- hpg_store %>%
  group_by(hpg_genre_name, hpg_area_name) %>%
  count()

p1 <- bar %>% 
  ggplot(aes(n)) +
  geom_histogram(fill='blue', binwidth = 1) +
  labs(x= 'Air genres per area')

p2 <- foobar %>%
  ggplot(aes(n)) +
  geom_histogram(fill='red' ,binwidth = 1) +
  labs(x='HPG genres per area')

p3 <- foo %>% 
  group_by(air_genre_name, air_area_name) %>% 
  summarise(mean_log_visit = mean(log1p(visitors))) %>% 
  left_join(bar, by = c('air_genre_name', 'air_area_name')) %>% 
  group_by(n) %>% 
  summarise(mean_mlv = mean(mean_log_visit),
            sd_mlv = sd(mean_log_visit)) %>% 
  replace_na(list(sd_mlv = 0)) %>% 
  ggplot(aes(n, mean_mlv)) +
  geom_point(color = 'blue', size = 4) +
  geom_errorbar(aes(ymin = mean_mlv - sd_mlv, ymax = mean_mlv +sd_mlv), width = 0.5, size = 0.7, color = 'blue') +
  labs(x = 'Cases of identical Air genres per area', y = 'Mean +/- SD of\n mean log1p visitors')


layout <- matrix(c(1,2,3,3), 2,2, byrow=T)
multiplot(p1, p2, p3, layout=layout)


# 결과 
# - 위의 차트 : 동일 지역에 있는 개별 장르의 수는 'air'와 'hpg' 데이터 셋의 경우 2와 1의 최대값으로 부터 급격하게 빠질것 .
# - 장르가 많은 쪾으로 꼬리가 길게 빠지는 모양이 나오고, 2번째 피크는 'air'8, 'hpg'는 13쯤. 


# 5.4 Reservation VS Visites

# 'air_reserve'와 'hpg_reserve' data set의 예약자 수를 확인해보자.
# 4.2 & 4.3 섹션에서 이들의  time-serise와 분포를 봤고, 여기서는 예약자 수와 실제 방문 고객간을 비교할 것.
# 각각의 레스토랑 'id'와 'air_visitor'파일을 summarise해서 일별 reserve_visitor(사람들 예약 건수)의 합계를 산출할 것.
# 'hpg reservation'을 포함하기 위해 'hpg_reserve'에서 'air_store' id에 해당하는 'hpg_store' id를 조인한 'store_ids'를 사용하자.

foo <- air_reserve %>%
  mutate(visit_date = date(reserve_datetime)) %>%
  group_by(air_store_id, visit_date) %>%
  summarise(reserve_visitors_air = sum(reserve_visitors))

bar <- hpg_reserve %>%
  mutate(visit_date = date(visit_datetime)) %>%
  group_by(hpg_store_id,visit_date) %>%
  summarise(reserve_visitors_hpg = sum(reserve_visitors)) %>%
  inner_join(store_ids, by = "hpg_store_id")

all_reserve <- air_visits %>%
  inner_join(foo, by = c("air_store_id", "visit_date")) %>%
  inner_join(bar, by = c("air_store_id", "visit_date")) %>%
  mutate(reserve_visitors = reserve_visitors_air + reserve_visitors_hpg)

class(foo$visit_date)
class(bar$visit_date)
# inner join 에서 둘의 문자형이 다르단 오류가 떠서 확인해봤는데, 똑같은데요 이사람아.

# 'air' 레스토랑의 실제 고객수에 대한 전체 reserve_visitor를 차트로 만들자. 
# ggExtra 패키지의 ggmarginal 함수를 사용해서 marginal histogram을 포함한 산포도 차트를 만들자. 
# 회색선은 'reserve_visitors == visitors'를 나타내고, 파란선은 linear fit임.

p <- all_reserve %>%
  filter(reserve_visitors < 120) %>%
  ggplot(aes(reserve_visitors, visitors)) +
  geom_point(color = 'black', alpha=0.5) +
  geom_abline(slope = 1, intercept = 0, color='gray60') +
  geom_smooth(method = 'lm', color='blue')

ggMarginal(p, type='histogram', fill ='blue', bins=50)

# 결과 
# - 히스토그램은 100이하의 범위에 국한해서 많은 분포가 몰려있음.
# - 산포도는 identity line을 크게 상회하고, 이건 예약하지 않은 고객이 더 많은 걸 나타냄. 
#   >> 대다수의 사람이 돌아다니다 가게를  방문하는 경우가 더 크기 때문에! 
# - 이 포인트에서 주목해야 할 부분은 아래 선인데, 몇몇 사람이 예약을 하고도 변심해서 방문하지 않는다는 것 
#   >> 노쇼가 예상될 수 있고, 이를 고려하는 것이 competition에서 해결해야 할 점 중 하나!!
# - 실제 방문객을 과소평가한 'reserve_visitors'의 수가 많은 이런 트렌드를 liner fit은 보여줌. 
#   >> 예약없이 방문하는 고객보다 더 많은 수의 예약이 캔슬되는 것을 예견할 수 있다. 


p1 <- all_reserve %>%
  ggplot(aes(visitors-reserve_visitors)) +
  geom_histogram(binwidth = 5, fill='bkack') +
  coord_flip() +
  labs(x=' ')

p2 <- all_reserve %>%
  ggplot(aes(visitors-reserve_visitors_air)) +
  geom_histogram(binwidth = 5, fill ='blue') +
  coor_flip() +
  labs(x = ' ')

p3 <- all_reserve %>%
  ggplot(aes(visitors-reserve_visitors_hpg)) +
  geom_histogram(binwidth = 5, fill ='red') +
  coor_flip() +
  labs(x = ' ')

p4 <- all_reserve %>% 
  ggplot(aes(visit_date, visitors - reserve_visitors)) +
  geom_hline(yintercept = c(150, 0, -250)) +
  geom_line() +
  geom_line(aes(visit_date, visitors - reserve_visitors_air +150), color = 'blue') +
  geom_line(aes(visit_date, visitors - reserve_visitors_hpg - 250), color = 'red') +
  ggtitle('Visitors - Reserved: all (black), air (blue), hpg (red)')

layout <- matrix(c(4,4,2,4,4,1,4,4,3),3,3,byrow=TRUE)
multiplot(p1, p2, p3, p4, layout=layout)

# 결과 
# - 이 차트는 training time 범위에서 의미있는 분산을 보여준다. 'air', 'hpg' 곡선이 대부분 기준선보다 위에 있지만 , 
# 두 데이터 셋을 결합하면 zero line에 가까운 분포의 평균을 볼 수 있다. 
# - 섹션 4.2와 비교해서 'air'의 예약이 차이가 없음을 볼 수 있다 .
#   >> 이것은 같은 트렌드를 따르고, 'air' reservations를 위한 프록시로 사용될 수 있다고 가정하는게 안전함을 ㅌ나타낸다. 


# 마지막으로, 예약자와 방문객 사이의 불일과 공휴일 간의 영향을 보자.
all_reserve %>%
  mutate(date = visit_date) %>%
  left_join(holidays, by = 'date') %>%
  ggplot(aes(visitors - reserve_visitors, fill = holiday_flg)) +
  geom_density(alpha=0.5)
# 결과 
# - 공휴일엔 예약후 방문객 보다는 바로 방문하는 사람이 많음을 볼 수 있다. 
# - 피크는 거의 동일하지만 , 큰 수에 대해서는 작지만 분명한 차이가 보임 .











 

 

source

www.kaggle.com/maestroyi/restaurant-visitor-forecasting-eda-with-r

 

Restaurant Visitor Forecasting EDA with R (한글 번역)

Explore and run machine learning code with Kaggle Notebooks | Using data from multiple data sources

www.kaggle.com

 

728x90
Comments