実務的課題と研究課題

本レポートでは、CRMを実行して収益性を向上させるという実務的課題を背景に、顧客idに基づいた購買データを分析する。したがって、研究課題は以下のものである。自社にとって、重要な顧客/顧客グループを特定する。ただし、ここで言う重要な顧客/顧客グループとは、購買額と購買頻度が高く、直近の購買日からの経過日数が少ない顧客/顧客グループとする。

データの概要と分析アプローチ

データの概要

本レポートにおけるデータは、2022idpos2.csvとid_data2.csvの2つのデータを用いたものである。前者は「顧客id、購買日、購買額、クーポン利用額」の変数を含み、2019年09月01日から2019年10月01日までの取引ごとに集計されたデータである。後者は3000人分の会員登録済み顧客情報であり、「顧客id、性別、年齢、家族構成」の変数を含むデータである。

分析アプローチ

分析アプローチの方針としては、RFM分析を採用する。RFM分析とは、最新の購買日、購買頻度、累積購買額を指標として分析する方法で、離反している可能性が低く、ロイヤルティが高い顧客を特定することができる。上述のように、本レポートでは、購買額と購買頻度が高く、直近の購買日からの経過日数が少ない顧客/顧客グループを特定するため、RFM分析は今回の分析目的を鑑みると、比較的適した分析アプローチであると言える。

分析結果

以下の手順で分析を進める。 1. 累積購買額が高い顧客を特定する。 2. 購買頻度が高い顧客を特定する。 3. 最新の購買日が近い顧客を特定する。

1. 累積購買額が高い顧客を特定する。

まず、2022idpos2.csvデータを用いて、累積購買額が高い顧客を特定する。2022idpos2.csvは上述のように取引ごとに集計されているデータなので、そのままの状態では重要顧客を特定しづらい。そこで、取引データを顧客idごとに集計して、顧客ベースのデータに変換する。その際、購買額の合計を「累積購買額」、顧客idの出現回数を「購買頻度」、2019年10月02日から最新購買日を引いたものを「最新購買日からの経過日数」として新たにな変数として定義して用いる。 累積購買額が高い顧客を特定するにあたって、デシル分析を用いる。デシル分析とは、累積購買額が高い順に10個のグループに分けて、ランクを割り振る分析である。本レポートでは、累積購買額が高いほど、高いランクを割り振った。その結果、上から2つのランク(10,9)に属する顧客グループで過半数の累積購買額を占めていることが判明した。また、最高ランク(10)に属する顧客群は圧倒的に累積購買額の割合が多いことが判明した。

library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.4
## ✔ forcats   1.0.0     ✔ stringr   1.5.0
## ✔ ggplot2   3.4.4     ✔ tibble    3.2.1
## ✔ lubridate 1.9.3     ✔ tidyr     1.3.0
## ✔ purrr     1.0.1     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(readr)
library(readxl)
idpos <- read_csv("/Users/maru_r14/Desktop/経営データ分析/マーケティング/mkt-reseach/simulation_data/2022idpos2.csv", na = ".")
## Rows: 5000 Columns: 4
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): date
## dbl (3): id, spent, coupon
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
idpos$datediff <- as.numeric(difftime("2019-10-02", idpos$date, units = "days"))
head(idpos)
## # A tibble: 6 × 5
##      id date      spent coupon datediff
##   <dbl> <chr>     <dbl>  <dbl>    <dbl>
## 1    38 2019/9/30  9265   926.        2
## 2    31 2019/9/10  7037   704.       22
## 3    20 2019/9/10  1790   179        22
## 4    30 2019/9/19  8450     0        13
## 5    42 2019/9/26  7052     0         6
## 6    41 2019/9/7   9340   934        25
idpos_cust <- idpos %>% 
  group_by(id) %>% 
  summarise(frequency = n(),
            monetary = sum(spent),
            cherry = sum(coupon),
            recency = min(datediff))
idpos_cust_m <- idpos_cust %>% 
  arrange(desc(monetary))

id_data <- read_csv("/Users/maru_r14/Desktop/経営データ分析/マーケティング/mkt-reseach/simulation_data/id_data2.csv")
## Rows: 5000 Columns: 4
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): gender
## dbl (3): id, age, famsize
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
str(id_data)
## spc_tbl_ [5,000 × 4] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ id     : num [1:5000] 1 2 3 4 5 6 7 8 9 10 ...
##  $ gender : chr [1:5000] "female" "female" "male" "female" ...
##  $ age    : num [1:5000] 32 37 22 21 49 43 46 46 56 56 ...
##  $ famsize: num [1:5000] 4 1 1 3 5 4 4 3 3 4 ...
##  - attr(*, "spec")=
##   .. cols(
##   ..   id = col_double(),
##   ..   gender = col_character(),
##   ..   age = col_double(),
##   ..   famsize = col_double()
##   .. )
##  - attr(*, "problems")=<externalptr>
idpos_cust <- left_join(idpos_cust, id_data, by = "id")

idpos_cust_m <- idpos_cust %>%
  arrange(desc(monetary))

idpos_cust_m$decile_rank <-
  cut(idpos_cust_m$monetary,
      quantile(idpos_cust_m$monetary, (0:10)/10,na.rm=TRUE),
      label=FALSE,include.lowest=TRUE)

decile <- idpos_cust_m %>%
  group_by(decile_rank) %>%
  summarize(freq = n(),
  monetary = sum(monetary))
total <- sum(decile$monetary)
decile2 <- decile %>%
  mutate(percent = monetary/total*100) %>%
  arrange(desc(decile_rank))
decile2
## # A tibble: 10 × 4
##    decile_rank  freq monetary percent
##          <int> <int>    <dbl>   <dbl>
##  1          10   279 14933505   36.4 
##  2           9   278  5642335   13.8 
##  3           8   277  4332863   10.6 
##  4           7   280  3793579    9.25
##  5           6   278  3289525    8.02
##  6           5   278  2823416    6.89
##  7           4   279  2351358    5.73
##  8           3   278  1820053    4.44
##  9           2   278  1292088    3.15
## 10           1   279   722426    1.76
theme_set(theme_gray(base_size = 10, base_family = "HiraMinProN-W3"))
head(idpos_cust_m)
## # A tibble: 6 × 9
##      id frequency monetary cherry recency gender   age famsize decile_rank
##   <dbl>     <int>    <dbl>  <dbl>   <dbl> <chr>  <dbl>   <dbl>       <int>
## 1    32        34   311439 21435.       1 male      45       5          10
## 2    49        34   241323 12250.       1 male      43       2          10
## 3    29        26   240559  8915.       1 male      45       2          10
## 4    38        24   215760  8644.       1 female    29       4          10
## 5    45        24   214573  7828.       1 female    29       3          10
## 6    10        28   214040 11258.       1 female    56       4          10
p2 <- ggplot(decile2, mapping = aes(x = decile_rank, y = percent))
p2 + geom_point() + labs(x = "ランク", y = "累積購買額割合", title = "散布図:ランクと累積購買額割合")

2. 購買頻度が高い顧客を特定する。

購買頻度が高い顧客を特定するにあたって、以下の仮説を置く。

仮説:累積購買額が高いほど、購買頻度が高い。

この仮説を検証するために、累積購買額と購買頻度の関係を調べる。横軸に累積購買額、縦軸に購買頻度をとって、図に表したものが以下である。

p4 <- ggplot(idpos_cust_m, mapping = aes(x = monetary, y = frequency))
p4 + geom_point() + labs(x = "累積購買額", y = "購買頻度", title = "散布図:購買額と購買頻度")

図からわかるように、購買頻度は累積購買額とかなり強い正の相関関係にあるので、上記の仮説は正しいと言えるだろう。

3. 最新の購買日が近い顧客を特定する。

最新購買日は顧客が離反したか否かを表す指標であるが、まずは上述のように、2019年10月2日を基準として、最新購買日からの経過日数の分布を確認する。

p0 <- idpos_cust_m %>% ggplot(mapping = aes(x = recency))
p0 + geom_histogram()  + labs(x = "経過日数", y = "頻度",title = "ヒストグラム1:最新購買日からの経過日数")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

上図からわかるように、かなりバラツキが大きいが、およそ半数以上は最新購買日からの経過日数が15日を過ぎていないことがわかる。

次に、最新購買日からの経過日数と購買頻度の関係を見ていく。その際に、デシルランクを用いて、色分けを試みた。

p5 <- ggplot(idpos_cust_m, mapping = aes(x = recency, y = frequency, color = decile_rank))
p5 + geom_point() + labs(x = "最新購買日からの経過日数", y = "購買頻度", title = "散布図:経過日数と購買頻度")

上図からわかるように、概ね、購買頻度が高いほど、最新購買日からの経過日数は小さいと考えられる。また、全体の傾向として、デシルランクが高いほど、最新購買日からの経過日数は小さいと言える。しかし、若干名デシルランクが高いにもかかわらず、最新購買日からの経過日数が大きい顧客がいる。具体的には、最新購買日からの経過日数が21日と28日の顧客群の中に数名存在する。これらの顧客は、1回の購買でかなりの購買額を費やすことが考えられるので、該当顧客の購買頻度を上昇させることで収益性の向上が見込めるとも言える。

まとめと実務的含意

基本的には、デシルランクが高い顧客が、購買額と購買頻度が高く、直近の購買日からの経過日数が少ない顧客グループに該当する。しかし、上述のように、一定数、デシルランクが高いにもかかわらず、購買頻度が低い顧客群が存在することも判明した。

ゆえに、以下の方策を提言しようと思う。

1.デシルランクが高い顧客の累積購買金額をさらに向上させる施策を実行する 2.デシルランクが高いのにもかかわらず、購買頻度が低い顧客群の詳細な特徴を把握して、購買頻度を向上させる施策を実行する