이 문서는 <비즈니스 데이터 분석:R>의 예제를 실습한 내용이다.

0. Analysis Framework

현상 : ‘퍼즐’ 게임 앱의 이번 달 매출이 감소하였다. 현상 : 이번 달에 광고집행 예산이 지난 달보다 적었다. 가설 : 광고 축소로 신규유저 매출이 감소했을 것이다.

신규유저 감소를 알아보기 위한 지표 - 신규 가입자 수 (install) - 신규가입 후 접속자 수 (dau/mau) - 신규가입자 중 paid-user - 신규가입자에게서 발생한 매출액

1. Load Data

library(data.table)
library(dplyr)
library(ggplot2)
library(scales)
library(pander)

path="/Users/jessymin/Desktop/BizDataAnalysis/R"

dau <- fread(file.path(path, "section3-dau.csv"))
dpu <- fread(file.path(path, "section3-dpu.csv"))
install <- fread(file.path(path, "section3-install.csv"))


2. Pre-processing

2-1. 데이터 확인

dau와 dpu 테이블이 day 단위로 unique user 처리된 것인지 여부를 먼저 확인한다.

dau.check=dau %>% 
        group_by(log_date) %>% 
        summarise(user=n(), 
                uniq.user=length(unique(user_id))
                )
dau.check <- mutate(dau.check, compare=user != uniq.user)
sum(dau.check$compare)
## [1] 0

unique user로 처리된 데이터이다. dpu 테이블에 대해서도 동일하게 확인해본다.

dpu.check <- dpu %>% 
        group_by(log_date) %>%
        summarise(user=n(), 
                  uniq.user=length(unique(user_id))
                  )
dpu.check <- mutate(dpu.check, compare=user != uniq.user)
sum(dpu.check$compare)
## [1] 56

dpu 테이블은 결제 건별로 저장되어 있어, user_id가 중복된다.

2-2. Reshape Data

dau <- dau %>% 
        select(-app_name) %>%
        mutate(log_month=substr(log_date, 6, 7))

dpu <- dpu %>% 
        select(-app_name) %>% 
        mutate(log_month=substr(log_date, 6, 7))

dpu2 <- dpu %>% 
        group_by(log_date, user_id) %>%
        summarise(pay_sum=sum(payment), pay_freq=n())

install <- install %>% 
        select(-app_name) %>%
        mutate(install_month=substr(install_date, 6, 7))
# Merge Data
dau_total <- dau %>% 
        inner_join(install) %>% 
        left_join(dpu2)

# Transfer NA
dau_total$pay_sum[is.na(dau_total$pay_sum)] <- 0
dau_total$pay_freq[is.na(dau_total$pay_freq)] <- 0

# Categorize paid/non-paid user
dau_total <- mutate(dau_total, paid_user="paid")
dau_total$paid_user[dau_total$pay_sum == 0] <- "non-paid"

# Categorize new/existing user
dau_total$new_user <- ifelse(dau_total$install_month == dau_total$log_month, "newby", "existing")

# Factorizing variables
dau_total$new_user <- factor(dau_total$new_user, c("newby", "existing"))
dau_total$install_month <- factor(dau_total$install_month, c("07","06","05","04"))



3. 데이터 분석

3-1. Executive Summary


일반적인 지표는 다음과 같다.

summary1 <- dau_total %>% 
                group_by(log_month) %>%
                summarise(MAU=length(unique(user_id)))

                
summary1 <- summary1 %>% inner_join(
                filter(dau_total, paid_user == "paid") %>%
                group_by(log_month) %>%
                summarise(MPU=length(unique(user_id)),
                                Revenue=sum(pay_sum)
                        )
                )

summary1 <- mutate(summary1, ARPU=round(Revenue/MAU)) %>%
                mutate(ARPPU=round(Revenue/MPU))


pander(comma(summary1))
log_month MAU MPU Revenue ARPU ARPPU
06 14,807 124 2,277,230 154 18,365
07 12,229 115 2,070,850 169 18,007


매출이 감소했으나, MAU의 감소로 ARPU는 소폭 상승했다.
ARPU : Average Revenue per User
ARPPU : Average Revenue per Paid User


다음으로 6월/7월 신규 가입자에 관한 지표를 상세히 살펴본다.

summary2 <- install %>% 
                filter(install_month %in% c("06", "07")) %>% 
                group_by(install_month) %>%
                summarise(total_user=length(user_id))

summary2 <- cbind(summary2, 
                (dau_total %>% 
                filter(new_user == "newby" & paid_user == "paid") %>%
                group_by(log_month) %>%
                summarise(paid_user=length(unique(user_id)),
                          Revenue=sum(pay_sum)) %>%
                select(-log_month)
                        )       
                )

summary2 <- summary2 %>% 
        mutate(ARPU=round(Revenue/total_user), 
               ARPPU=round(Revenue/paid_user))

pander(comma(summary2))
install_month total_user paid_user Revenue ARPU ARPPU
06 9,209 48 498,370 54 10,383
07 6,631 39 291,990 44 7,487


7월 신규가입자 수는 6월보다 감소했으며, 이에 따라 과금한 유저 및 발생 매출액도 감소했다.

3-1. 신규 가입자 수(Acquisition)

pal4 <- c("#08519c","#737373","#969696","#bdbdbd")
pal2 <- c("#0570b0", "#737373")


install_df <- install %>% group_by(install_month) %>%
        summarise(count=n())

ggplot(install_df, aes(install_month, count)) + 
        geom_bar(stat="identity", fill="steelblue", width=0.4) +
        geom_text(aes(label=comma(count)), vjust=-0.2, size=3.5) +
        scale_y_continuous(labels=comma) +
        ggtitle("New Registered User")

7월에 신규가입한 유저 수는 6월 대비 약 28%(2,578명) 감소했다.
신규유저 획득에 문제가 발생했다.

3-2. 활성화된 유저 중 신규 가입자 수 비율

먼저 7월에 전월 대비 활성화 유저가 얼마나 줄었는지 파악해 본다.

mau <- dau_total %>% group_by(log_month) %>%
        summarise(count=length(unique(user_id)))

ggplot(mau, aes(log_month, count)) + 
        geom_bar(stat="identity", fill="steelblue", width=0.4) +
        geom_text(aes(label=comma(count)),
                  vjust=-0.3, size=3.5) +
        scale_y_continuous(labels=comma) +
        ggtitle("MAU")

7월 활성화 유저는 전월 대비 2,578명 감소했다. 가입자 수 감소량과 같다.
가입월별로 자세히 살펴본다.

mau.install_month <- dau_total %>% 
        group_by(log_month, install_month) %>%
        summarise(count=length(unique(user_id)))

ggplot(mau.install_month, aes(log_month, count, fill=install_month)) + 
        geom_bar(stat="identity", width=0.4) +
        geom_text(aes(label=comma(count)), 
                  size=3.5,
                  position=position_stack(vjust=0.5)) +
        scale_y_continuous(labels=comma) +
        scale_fill_manual(values=pal4) +
        ggtitle("MAU by Registered Month")

mau.new_user <- dau_total %>% 
        group_by(log_month, new_user) %>% 
        summarise(count=length(unique(user_id)))

ggplot(mau.new_user, aes(log_month, count, fill=new_user)) + 
        geom_bar(stat="identity", width=0.4) +
        geom_text(aes(label=comma(count)), 
                  size=3.5,
                  position=position_stack(vjust=0.5)) +
        scale_y_continuous(labels=comma) +
        scale_fill_manual(values=pal2) +
        ggtitle("MAU by User Type")


3-4. 신규 가입자에게서 발생한 매출액

df <- dau_total %>% 
        group_by(log_month, install_month) %>%
        summarise(total_payment=sum(pay_sum))

ggplot(df, aes(log_month, total_payment, fill=install_month)) +
        geom_bar(stat="identity", width=0.4) +
        geom_text(aes(label=comma(total_payment)),
                  position=position_stack(vjust=0.5),
                  size=3.5) +
        scale_y_continuous(labels=comma) + 
        scale_fill_manual(values=pal4) +
        ggtitle("Revenue per Registered Month")

df <- dau_total %>% group_by(log_month, new_user) %>%
        summarise(total_payment=sum(pay_sum))

ggplot(df, aes(log_month, total_payment, fill=new_user)) +
        geom_bar(stat="identity", width=0.4) + 
        geom_text(aes(label=comma(total_payment)),
                  position=position_stack(vjust=0.5),
                  size=3.5) +
        scale_y_continuous(labels=comma) +
        scale_fill_manual(values=pal2) +
        ggtitle("Revenue per User Type")

기존 유저로부터 발생한 매출액 역시 동일하게 셋팅되어 있다. 의도적으로 셋팅한 것이 확실하다.

따라서 더 이상의 디테일한 분석은 하지 않고 실습을 여기서 마무리하기로 한다.