目次
こんにちは、美容室経営研究所Refineの井上です。今回は美容室の顧客が離反してしまう傾向を探るための分析を、生存時間分析で行っていこうと思います。
カプランマイヤー曲線とCox比例ハザードモデルを使用します。
データの読み込みと説明
読み込み
まずは必要なモジュールのインポートとデータセットの読み込みを行います。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import japanize_matplotlib
data = pd.read_excel('customer_survival_data.xlsx')
data
各変数について説明します。
- 「近隣居住」は、顧客が近隣に居住しているかを表しています。例えば、住所から同じ市内かどうかなどの指標が使えそうですね。以下の変数も同様で、Yesが1でNoが0です。
- 「販促メール登録」は、顧客が店舗からの販促メールの受信を登録しているかどうかです。
- 「カットのみ」は、いつも施術するメニューがカットであり、カラーやパーマを行わない、という変数です。
- 「就業」は、顧客が仕事をしているかどうかの変数です。
- 「経過日数(最終来店)」は、最終来店からどのくらいの日数が経過しているか、という変数です。
- 「経過日数(登録)」は、店舗に会員登録してから、つまり初回来店からどのくらいの日数が経過しているかです。
- 「離反」は、今回の分析に目的変数であり、顧客が失客に判定されているかどうかの変数です。今回は1年(365日)来店しなければ失客したと判定することにしましょう。
上記の変数について顧客のデータが900名分あるクロスセクションデータです。
仮説を立ててみる
ここでデータについて仮説を立ててみましょう。
感覚ですが、なんとなく家が近い方が、販促メールを受け取っている方が、来店が促進されて失客になりにくい気がします。
つまり、係数はマイナスで出力されそうですね。
EDA(Explanatory Data Analysis)
顧客IDは変数ではないため、インデックスとします。
data = data.set_index('ID')
data
次に要約統計量を表示してみます。
data.describe()
平均を見る限り、どの変数も偏った分布にはなっていなさそうですね。
今回のデータでは、約半数に顧客が離反してしまっているようです。
分析
カプランマイヤー(その1)
分析に入っていこうと思います。
経過日数は2種類ありましたね。最終来店か初回かです。
まずは初回からの経過日数を用いてカプランマイヤー曲線を描いてみます。
カプランマイヤー推定器の数式は以下の通りです。
\begin{equation}
S(t) = \prod_{t_i \leq t} \left(1 – \frac{d_i}{n_i}\right)
\end{equation}
ここで、
- S(t) は時間 t までの生存関数です。
- ti は少なくとも1つのイベント(失客)が発生した時点を表し、これらは t までのすべての時間点について考慮されます。
- di は時間 ti にイベントが発生した顧客数です。
- ni は時間 ti にリスクセットに残っている数です(つまり、時間 ti までにまだ失客していない顧客数です)。
data_1 = data.drop('経過日数(最終来店)', axis=1, inplace=False)
data_1
不要な変数を落として、使用するデータセットとします。
次にカプランマイヤーですが、lifelinesのKaplanMeierFitterというモジュールを使用します。
ついてに後で使うことになるCox比例ハザードモデルもインポートしておきましょう。
plot_lifetimesは描画のためのものです。
from lifelines import KaplanMeierFitter, CoxPHFitter
from lifelines.plotting import plot_lifetimes
# カプラン-マイヤー分析
kmf = KaplanMeierFitter()
# 生存時間とイベントでフィットする
kmf.fit(durations = data_1['経過日数(登録)'], event_observed = data_1['離反'])<lifelines.KaplanMeierFitter:”KM_estimate”, fitted with 900 total observations, 461 right-censored observations>
学習が完了しました。
次にプロットしてみます。
#カプラン-マイヤー曲線のプロット
kmf.plot_survival_function()
plt.title('カプランマイヤー曲線')
plt.ylabel('生存確率')
plt.xlabel('Days')
plt.axvline(x=365, color='green', linestyle='--')
plt.show()
離反の閾値である365日のところに垂線を緑の破線で引きました。
時間が経過するほどにどんどん失客していくのがわかりますね。
しかし、これは初回来店からの日数で生存をプロットしてしまっています。
最終来店から365日で失客判定しているのに、全期間を変数として用いるのはなんだか違和感があります。
調べたところ、上記の方法でもいいのだけれど、顧客の離反分析には最終来店の方を用いるのが一般的なようです。
カプランマイヤー(その2)
ということで、データセットを変更して再度カプランマイヤー曲線をプロットします。
#データセット変更
data_2 = data.drop('経過日数(登録)', axis=1, inplace=False)
data_2
# カプラン-マイヤー分析
kmf_2 = KaplanMeierFitter()
# 生存時間とイベントでフィットする
kmf_2.fit(durations = data_2['経過日数(最終来店)'], event_observed = data_2['離反'])<lifelines.KaplanMeierFitter:”KM_estimate”, fitted with 900 total observations, 461 right-censored observations>
#カプラン-マイヤー曲線のプロット
kmf_2.plot_survival_function()
plt.title('カプランマイヤー曲線')
plt.ylabel('生存確率')
plt.xlabel('Days')
plt.axvline(x=365, color='green', linestyle='--')
plt.show()
先ほどより傾きが急になりましたね。
生存確率が50%のところが約600日地点で、そこまで一気に減少しているようです。
365日を超えた時点でガンガンアプローチして顧客を少しでも繋ぎとめるのが一つ手かもしれません。
また、もしかしたら365日よりも前に急落するポイントがあるのかもしれないので、閾値を変えてみるのもありかもしれないですね。
