tl;dr

  • PUBG-M의 출시는 다른 게임의 매출에 일시적인 타격은 주었으나, 지속적인 충격을 주지 못한 것으로 보인다.

NOTICE

  • 문제가 생길 경우 글은 언제나 예고 없이 수정되거나 사라질 수 있습니다. 이 점 양해 바랍니다.

Update history

  • 20180620 최초 작성
  • 20180621 PUBG-M 매출 자료 추가

Motivation

“배틀그라운드 모바일”(이하 PUBG-M)의 엄청난 다운로드 숫자를 보다가, 문득 궁금해졌다. 저 정도의 다운로드 숫자라면 분명 기존 모바일 게임 매출에 영향을 주지 않았을까? 일단 그림을 몇 개 그려보자.

Data Desc.

활용한 데이터에 대한 간략한 정보은 다음과 같다.

  • 자료의 출처는 AppAnnie.com
  • 한국의 iOS와 AOS 통합 자료를 사용 (한국 시장에서 게임 앱의 안드점유율은 대략 85% 이상)
  • PUBG-M 출시일인 2018년 5월 16일을 전후로 4주씩 데이터 수집

해당 데이터는 github repo에 공유했다. 원자료를 가공해 분석에 활용할 수준으로 가다듬은 자료를 면저 로딩하도록 하자. 아래 코드는 분석에 필요한 패키지 및 전처리가 완료된 rds 파일을 로드하는 코드다. CP949로 인코딩된 csv 확장자 파일도 올려 두었다. 이 부분은 각자 알아서 수정해 활용하기 바란다.1

c("tidyverse", "wrapr", "here", "lubridate", "ggsci", "patchwork") -> packages 
lapply(packages, library, character.only = TRUE)

"./rds/appannie_reduced.rds" %>% readRDS() -> tbl0

Data preparation

그림을 그리기 위해서 데이터를 더 다듬어야 한다. 아래 코드를 참고하자.

tbl0 %>% dplyr::filter(!is.na(rank)) -> tbl1 

tbl1 %>% 
  select(
    -one_of("rank", "value", "unit")
  ) %>% 
  distinct( 
    app_name, date, .keep_all=TRUE  
  )-> common 

tbl1 %>% 
  select(one_of("rank", "value", "unit", "app_name", "date")
  ) %>% 
  dplyr::filter(unit == "Downloads") %>% 
  rename(
    download = value, 
    rank_dl = rank
  ) %>% 
  select( 
    -unit
  ) -> download

tbl1 %>% 
  select(
    one_of("rank", "value", "unit", "app_name", "date") 
  ) %>% 
  dplyr::filter(unit == "USD") %>% 
  rename(
    revenue = value, 
    rank_rv = rank
  ) %>% 
  select(-unit) -> usd

download %>% 
  left_join(usd, by = c("app_name", "date")) %>% 
  select(rank_dl, rank_rv, app_name, date, revenue, download) %>% 
  left_join(common, by = c("app_name", "date")) -> tbl0 

tbl0 %>% 
  distinct(date) %>% 
  mutate( 
    year = year(date) 
  ) %>% 
  group_by(year) %>% 
  mutate(
   n_date = seq_len(n())
  ) -> date

tbl0 %>% 
  mutate(
    year = year(date)
  ) %>% 
  left_join(
    date, by=c("date", "year")
  ) -> tbl1 

# break setting 
c(0, 3, 25, 100, 1000) -> mybreaks 
c("t3", "t25", "t100", "remain") -> mylabels

my_cut <- function(vc, breaks0=mybreaks, labels0=mylabels){
  cut(vc, breaks = breaks0, labels=mylabels) 
}
summarise_bg <- function(year0, df, do_daily=T){
  df %>% 
    dplyr::filter(year == year0, !is.na(revenue)) %>% 
    group_by(date) %>% 
    arrange(date, -revenue) %>%
    mutate(
      rank_rv2 = seq_len(n()), 
      cat_rv = my_cut(rank_rv2)
    ) %>% 
    group_by(date, cat_rv) %>% 
    summarise(
      sum_rv = sum(revenue), 
      fct_bg = if_else(first(n_date) <29, "BBG", "ABG"), 
      n_date = first(n_date)
    )
}

summarise_bg(2018, tbl1) %>% mutate(year = year(date)) -> tbl2 
summarise_bg(2017, tbl1) %>% mutate(year = year(date)) -> tbl3
bind_rows(tbl3, tbl2) %>% as_tibble(.) -> tbl4 

ymd("2017-05-01", "2017-05-02", "2018-05-01", "2018-05-02",
    "2017-06-01", "2017-06-02", "2018-06-01", "2018-06-02") -> dates_ex

tbl4 %>% 
  dplyr::filter(!date %in% dates_ex) %>%
  group_by(n_date, cat_rv) %>% 
  summarise(dff = sum_rv[2] - sum_rv[1]) -> tbl5 

Downloads Score of PUBG-M

tbl0 %>%
  mutate(
    is_topdl = if_else(rank_dl==1, TRUE, FALSE)
  ) %>% 
  group_by(date, is_topdl) %>% 
  summarise(
    download = sum(download)
  ) %>% 
  group_by(date) %>% 
  mutate(
    download_top = download[is_topdl==T],
    shr_top = download_top / sum(download)
  ) -> topdl 

topdl %>% 
  dplyr::filter(date >= ymd("2018-01-01")) %>% 
  ggplot() + 
  aes(x=date, y=download_top) +
  geom_col(alpha=0.5) + 
  geom_vline(xintercept=ymd("2018-05-16"), col="black", size=1, alpha=0.5, linetype=1) +
  ggtitle("#1 Downloaded Mobile App (2018)") + 
  xlab("date") + 
  ylab("number of downloads") -> p_dl1

topdl %>% 
  dplyr::filter(date >= ymd("2018-01-01")) %>%
  ggplot() + 
  aes(x=date, y=shr_top) +
  geom_col(alpha=0.5) +
  geom_vline(xintercept=ymd("2018-05-16"), col="black", size=1, alpha=0.5, linetype=1) +
  ggtitle("The Share of #1 Mobile App (2018)") + 
  xlab("date") + 
  ylab("share of #1 app")-> p_dl2 

topdl %>% 
  dplyr::filter(date < ymd("2018-01-01")) %>% 
  ggplot() + 
  aes(x=date, y=download_top) +
  geom_col(alpha=0.5) +
  ggtitle("#1 Downloaded Mobile App (2017)") + 
  xlab("date") + 
  ylab("number of downloads") -> p_dl3

topdl %>% 
  dplyr::filter(date < ymd("2018-01-01")) %>%
  ggplot() + 
  aes(x=date, y=shr_top) +
  geom_col(alpha=0.5) +
  ggtitle("The Share of #1 Mobile App (2017)") + 
  xlab("date") + 
  ylab("share of #1 app")-> p_dl4

((p_dl1 | p_dl2) / (p_dl3 | p_dl4)) & scale_fill_simpsons() & theme_minimal()  

상단의 그림 두 개가 PUBG-M 출시를 전후한 게임 1위 앱의 다운로드 숫자와 데이터에 기록된 해당일 다운로드 총 규모에서 1위 앱의 비율을 나타낸 것이다. 회색 선은 PUBG-M 출시일인 5월 16일을 의미한다. PUGBM 출시 이후 다운로드 숫자와 비중 모두 압도적이다. 이글을 작성하고 있는 2018년 6월 20일 기준으로 PUBG-M가 여전히 다운로드 1위이다. PUBG-M의 기록이 이례적이라는 사실을 독자는 아래 두 개의 그림으로 확인할 수 있다. 작년 같은 기간에 기록한 최고 다운로드 숫자는 대략 PUBG-M에 비해서 70만 건 이상 낮다.

PUBG-M vs Incumbents

여가는 돈과 더불어 시간을 소모하는 활동이다. 돈이라는 제약에는 개인별로 큰 차이가 있지만 시간은 대체로 개인별 차이가 작다. 아울러 시간의 제약은 돈의 제약에 비해 탄력적이지 못하다. 아무리 게임을 좋아해도 하루에 24시간 이상 게임할 수는 없다. 모바일 이용자가 PUBG-M를 하느라 다른 게임을 하지 않았다면, 기존 게임의 점유율이 줄어들고 이에 따라서 매출도 줄어들게 될 것이다. 물론 이런 현상이 관찰되기 위해서는 몇가지 사전 조건이 성립해야 한다.

  1. 기존 모바일 게임과 PUBMG 사이에 일정 수준 이상의 경합관계가 존재해야 한다.
  2. 1이 일정 수준 이상의 과금 이용자 사이에서 존재해야 한다.

일단 그림부터 살펴보자.

tbl2 %.>% 
  ggplot(.) + 
  aes(x=date, y=sum_rv, color=cat_rv) +
  geom_point(alpha = 0.5) +
  geom_line(alpha = 0.5) + 
  stat_smooth(geom="line", alpha=0.6, size=2, span=0.5) + 
  geom_vline(xintercept=ymd("2018-05-16"), col="black", size=1, alpha=0.5, linetype=1) +
  ggtitle(str_glue("Before and After PUBG Mobile")) + 
  xlab("date") + 
  ylab("revenue(USD)") -> p_2018

tbl3 %.>% 
  ggplot(.) + 
  aes(x=date, y=sum_rv, color=cat_rv) +
  geom_point(alpha = 0.5) +
  geom_line(alpha = 0.5) + 
  stat_smooth(geom="line", alpha=0.6, size=2, span=0.5) + 
  #geom_vline(xintercept=ymd("2018-05-16"), col="black", size=1, alpha=0.5, linetype=1) +
  ggtitle(str_glue("Korean Mobile Market 2017")) + 
  xlab("date") + 
  ylab("revenue(USD)") -> p_2017

tbl5 %.>% 
  ggplot(.) + 
  aes(x=n_date, y=dff, color=cat_rv) +
  geom_point(alpha = 0.5) +
  geom_line(alpha = 0.5) + 
  stat_smooth (geom="line", alpha=0.6, size=2, span=0.5) + 
  geom_vline(xintercept = 29, size=1, alpha=0.5, col="black", linetype=1) +
  ggtitle("DID of PUBG Mobile") + 
  xlab("date count") + 
  ylab("revenue difference(USD)") -> p_did
# Y2018 trend of Before and After PUBG Mobile
p_2018 + theme_minimal() + scale_color_simpsons()

p_2017 + theme_minimal() + scale_color_simpsons()

상황을 단순화해 살펴보기 위해서 게임 매출 순위에 따른 범주 구분은 다음과 같이 정했다.

  1. 1~3위
  2. 4위~25위
  3. 26위~100위
  4. 100위 이하

이 범주에 따라서 2018년 5월 16일에 출시된 PUBG-M 전후로 다른 게임의 매출 변화를 살펴보자. PUBG-M 출시 이후 10일 정도 범주 1,2의 하락세가 관찰된다. 물론 결론을 내긴 이르다. 모바일 게임 매출에는 월별 주기가 존재한다. 월초를 정점으로 해서 말까지 떨어지는 추세가 일반적인데, PUBG-M 춭시 이후 이러한 추세가 관찰된 것인지 PUBG-M의 영향인지 구분하기 힘들다. PUBG-M 출시 이후 다른 게임 매출에 영향을 주었을 여러가지 다른 요인을 통제할 방법이 없다.

DID of PUBG-M

이런 상황에서 쓸 수 있는 계량경제학 기법이 DID(difference in difference)다. 이는 같은 혹은 유사한 대상에 대해서 자연실험 혹은 관심 상황이 발생하기 이전의 비교 가능한 시점을 정해 둘 간의 ’차이에 차이’가 있는지를 살펴보는 것이다. 만일 상황이 영향을 끼쳤다면 DID에서 차이를 관찰할 수 있게 될 것이다.

이를 위해 2018년 해당 기간과 같은 같은 요일로 매칭되는 2017년 매출 자료를 구했다. 2017년과 2018년 비슷한 시기의 매출 차이를 살펴보면 PUBG-M의 DID를 대략 파악할 수 있다. 다만, 월초 높은 매출이 가져오는 효과를 배제하기 위해서 각 연도 자료에서 1일과 2일은 제외했다.

# Y2018 trend of Before and After PUBG Mobile
p_did + theme_minimal() + scale_color_simpsons()

위 그림에서 보듯이 PUBG-M 출시의 타게임에 대한 매출 타격은 출시 이후 초반 10일 정도까지만 존재한 것 같다. 타격의 낙폭은 1 범주(~3위)보다는 2 범주(~25위)에서 두드러졌다. PUBG-M의 게임 속성을 고려하면 매출 상위에 주로 포진한 하드코어한 게임들 보다는 2 범주에 있는 게임과의 경합 관계는 어느 정도 타당해 보인다. 이러한 PUBG-M 효과는 10일 이후 다시 원래 수준으로 돌아오는 것으로 나타난다. 다만 이렇게 회귀한 내용에 대해서 판단하기 위해서는 보다 엄밀한 분석과 추정이 필요하다. 다만 2017년 같은 기간 시장이 전체적으로 하락세였던 것과는 대조적으로 2018년 상승을 기록한 대목은 PUBG-M의 여파를 회복하는 과정으로 이해될 수 있다.

What’s Next?

지금까지 DID 추정의 가능성을 살피기 위해서 빨르게 그림 몇 개 그려보았다. PART 2에서는 회귀분석을 통해 DID 추정량을 살펴볼 예정이다. 언제 PART 2를 들고 올지는 나도 모른다!

Bonus track

그래서 PUBG-M의 매출은? 700만에 육박하는 다운로드에 비해서는 처참한 수준이다. 현재 매출 1위인 “리니지M”과 비교하면 1%에서 3% 사이를 오락가락하고 있다…

tbl0 %>%
  dplyr::filter(rank_rv==1|app_name=="PUBG Mobile", date >= ymd("2018-01-01")) %>%
  group_by(date) %>% 
  dplyr::filter(n() == 2) %>% 
  group_by(date) %>% 
  summarise(
    rev = revenue[app_name=="PUBG Mobile"],
    shr = rev / revenue[rank_rv==1]
  ) %>% 
  ggplot() + 
  aes(x=date, y=rev) + 
  geom_col(alpha=0.5) +
  ggtitle("Revenue of PUBG-M") + 
  xlab("date") + 
  ylab("USD") + 
  scale_fill_simpsons() + theme_minimal()  


  1. 만일 위의 깃헙레포를 포크 혹은 클론했다면, root의 bg-effect.Rproj을 RStudio에서 실행 한 후 아래의 코드를 그대로 실행하라. 많은 R의 선지자가 강조하듯이 setwd()는 안 쓰는게 정신 건강에 좋아!