データの向こうに見える世界

戦略コンサルとデータマイニング

入退会データ分析(2) 教室別の累積入会者数推移

 みなさま、こんにちは。

 前回に続いて、今回は教室毎の累積入会者数の推移を可視化してみたいと思います。

データの読み込み

 まずは例によってデータの読み込みから。 

 合わせて、教室コードのリストも作成しておきます。

setwd("~/Desktop")
library(readxl)
dataset <- read_excel("~/Desktop/データ分析/データ/yobiko/yobiko.xlsx")

class_list <- sort(unique(dataset$教室コード))

 ちなみに、教室数は208教室らしいです。

> length(class_list)
[1] 208

 

データ整形(1):教室毎の入会者数推移

箱を用意する

 ここからデータの整形をしていきます。

 最初に、対象月の一覧と教室毎の入会者数推移を格納するための箱を用意しておきます。

# 分析(2): 教室別の特徴分析
## 2-1: 教室毎の在籍数推移
### 2-1-1: データ整形(1): 教室毎の入会者数推移
Date <- sort(unique(dataset$適用年月))
class_inflow <- matrix(NA, nrow= length(class_list), ncol= length(Date))
colnames(class_inflow) <- Date
rownames(class_inflow) <- class_list
  • Date: 「適用年月」を小さい順に並べたもの
  • class_inflow: 教室毎の入会者数を格納する行列(縦:教室/横:対象月)

 class_inflowには初期値としてNAを入れています。

数値を入れていく

それでは、用意した箱に実際に入会者数を入れていきましょう。

#教室コードを指定した時に入会者or退会者数の推移を返す関数を定義
class_count = function(classcode, type){ 
  flow_count <- table(dataset$適用年月[(dataset$申込種別 == type) & (dataset$教室コード == classcode)])
  flow.vec <- rep(NA, length(Date))
  names(flow.vec) <- Date
  if(length(flow_count) != 0){
    flow.vec[which(names(flow.vec) == names(flow_count[1])):which(names(flow.vec) == names(flow_count[length(flow_count)]))] <- 0 
  }
  flow.vec[match(names(flow_count), names(flow.vec))] <- flow_count
  return(flow.vec)
}

for(i in class_list){
  class_inflow[rownames(class_inflow) == i,] <- class_count(i, "In") 
}

 ここでは、教室コードと入退会のフラグ("In"/"Out")を引数に渡すと、入退会者数推移をベクトルで返してくれる関数を定義しています。(関数class_count)

 関数の中身は下記の通り。

  1. flow_countに、指定した教室コード・入退会フラグと合致するデータの集計値を格納する
  2. 対象月と同じ長さのベクトルflow_vecを用意し、とりあえずNAを入れておく
  3. flow_countが空でない場合に、flow_countで条件に合致した適用年月の最初から最後までの期間に対して、flow_vecに0を入れる*1
  4. 最後に、flow_countで集計した数値をflow_vecに引き渡し、関数を呼び出した際にflow_vecを返すように指定する

 あとは、for文で各教室毎に計算した結果を先ほど作った箱(class_inflow)に入れていけば終了です。

 

データ整形(2):カウント時期を揃える

入会者が入ってから初めての4月に頭を揃える

 教室毎の入会者数の推移は取れたのですが、これから分析していく際に、各教室での開校年月のずれを考えると、できれば開校年月毎にデータを揃えていきたい所です。

 季節性がなければ、初めて入会データがあった月を頭に揃えればなんとなく出来るのですが、前の記事で見たように入会者数は4月と9月にピークがあるようなので、今回は年度頭という事で4月に統一していきたいと思います。

 という事で、各教室での入会者数推移ベクトル(x)を引数に渡した時に、良い感じにカウント時期を揃えて出してくれる関数adjustを定義します。

### 2-1-2: データ整形(2): カウント時期揃え
adjust <- function(x){
  #入会者が入ってから初めての4月に頭の時期を揃える
  size <- length(x)
  first.time <- which(x != 0)[1] #初めて入会者が入った月番号
  if(is.na(first.time) == TRUE){
    first.time <- x[1]
  }
  year <- as.numeric(substring(names(first.time), 1, 4))
  month <- as.numeric(substring(names(first.time), 5, 6))
  
  
  if(month <= 4){
    adjust.time <- paste(year, "04", sep="")
  }else{
    adjust.time <- paste(year + 1, "04", sep="")
  }
  
  X <- x[-(1:(which(Date == adjust.time)-1))]
  X <- c(X, rep(NA, size-length(X)))
  return(X)
}

 関数の中身は下記の通り。

  1. sizeに入会者数推移ベクトル(x)の長さを記録
  2. first.timeに初めて入会があった月を記録(もし一度も入会がなければ対象月の最初を抜き出して記録)
  3. yearmonthfirst.timeに保存された年月データ(ex."20170801")から年と月を記録
  4. あとはmonthが4月を超えているか否かで場合分けして、カウント時期以前のデータを切り出す(切り取った分はベクトルの末尾にNAとして補完)

累積入会者数の推移を計算する

 良い感じの関数が出来たので、class_inflowに対してapply関数*2を使ってばちばち処理します。

class_inflow_adjust <- t(apply(class_inflow, 1, adjust))
matplot(t(class_inflow_adjust), type= "l")
class_instock_adjust <- t(apply(class_inflow_adjust, 1, cumsum)) #教室別の累積入会者数
matplot(t(class_instock_adjust), type= "l")

 class_inflow_adjustに処理結果を入れ込みます。

ここまで出来れば、教室別の累積入会者数を計算してclass_instock_adjustに入れたらデータ整形は終了です。

 

累積入会者数の可視化

 今回は、Rのmatplot関数でざっくりデータを見てみましょう。

cumulative_total_of_enrollees <- t(class_instock_adjust)
matplot(cumulative_total_of_enrollees, type= "l")

 出てきたグラフはこんな感じです。

 ▼教室別の累積入会者数推移(全教室)

f:id:mochi1441:20170801183111p:plain

 ごちゃごちゃしてます。。。笑

 一応教室の部門別にも出して見ました。

▼教室別の累積入会者数推移(部門:A)

f:id:mochi1441:20170801184318p:plain

▼教室別の累積入会者数推移(部門:B)

f:id:mochi1441:20170801184329p:plain

▼教室別の累積入会者数推移(部門:C)

f:id:mochi1441:20170801184338p:plain

▼教室別の累積入会者数推移(部門:F)

f:id:mochi1441:20170801184351p:plain

 こうして見てみると、ちゃんと分析できそうなのは部門B, Cあたりしかなさそうですね。。。笑

 

 特に部門Bの推移を見てみると、なんとなくですがうまく集客できている層と低空飛行で徐々に生徒を獲得している層に別れているように見えます。

f:id:mochi1441:20170801190745p:plain

 ここで、部門Bの教室に関しては、なんらかの要因で集客成功層と低空飛行層で分岐しているのでは?と仮説を立てられます。

 となれば、集客が成功している層と低空飛行層の条件の違いを探し出し、さらに分析を進めれば教室全体での集客力アップに繋がるヒントが得られるかもしれませんね。

 というわけで、今回はここまで。

折角なので、次回は部門Bの教室に対し、集客成功層と低空飛行層を自動で振り分けるコードを書いて見たいと思います。

 

 念のため。。ですが、本ブログは色々なデータをRを使っていじりながら色々な分析を試みる事が目的です。特に今までエクセルでしかデータを触ったことがない方が、Rを使って具体的にどんな操作ができるのか知って頂けたらと思って書いています。

 そのため、実際のデータ分析とは異なり、実験的にデータをいじっておりますので悪しからず。。。

 データ分析の現場では、最初に課題や解きたいテーマがある上で、入念に作業設計してから分析を始めます。とりあえず色々データを回してみようという思想は大変危険です!

 そのあたりのマインドセットやデータ分析の手順に関してもいずれ記事に出来ればと思いますので、引き続き宜しくお願い致します。

 

以上

 

*1:なぜこんな処理をしているかというと、flow_vecには初期値でNAを入れていますが、各月での入退会者数が本当に0だったのか、そもそも教室が開校していなかったのかを区別するため、前後で入会・退会のある明らかに開校中の期間に関しては明示的に0と入れておきたいからです。

*2:apply関数を使った処理は以前の記事を参考にしてください。