フリーミアムのSaaSやWebサービスのビジネスの顧客のチャーン(離脱)を判別する方法

ビジネスの形態を問わず、新規に顧客を獲得し、その顧客に自分達のサービスやプロダクトを継続的に利用してもらうことは、ビジネスの効率の観点から重要です。

一方で、広告などで収益をあげるようなWebサービスのユーザーや、フリーミアムのモデルを採用するSaaSサービスの無料ユーザーは、そもそも費用を払わずにサービスなどを利用しているため、顧客のチャーン(解約)に相当するような明確なイベントが発生しません。

従って、そのようなビジネスにおいて顧客のチャーン(離脱)を理解したいときには、顧客がチャーンしているのかどうかを判定するルールを定義する必要があります。

そこでこのノートでは、2つの方法を利用して、顧客のチャーンを判定する方法を紹介します。

チャーン判定のルール

今回は、以下2つの方法でチャーンを判定する方法を紹介します。

  1. 最後の利用タイミングからの経過時間でチャーンを判定する
  2. 顧客ごとの利用間隔からチャーンを判定する

利用データ

今回はフリーミアムのSaaSサービスやWebサービスなどのビジネスdでも取得ができることが多い、サービスの利用ログの情報を利用します。

データの準備

POSIXct(日付時間)型のデータを日付型に変換する

今回は時間の情報は不要なので、日付型にデータを変換します。

アクセス日時の列ヘッダーメニューから、データタイプを変換、Date(日付)タイプに変換を選択し、実行します。

日付型に変更することができました。

データ上の最新の日付を取得する

実際にデータ上の最新の日付を取得していきます。

timestampの列ヘッダーメニューから計算を作成を選択します。

計算を作成(Mutate)のダイアログが表示されたら、計算エディタに以下のようにタイプします。

max(timestamp)

このとき、新しく列を作成にチェックを付けて、列名に任意の名称をつけ実行します。(今回はlast_dayという名前を付けています)

このデータ上の最新の日付情報を取得することができました。

ここから2つ方法でチャーンを判定していきます。

1. 最後の利用タイミングからの経過時間でチャーンを判定する

これはよりシンプルなやり方で、例えば、直近30日の間サービスの利用がなければ、チャーンしているものと判定するやり方です。

こちらは以下の情報を集計することで簡単にチャーンを判定することが可能です。

  • そのデータの最新の日付
  • 顧客ごとの最後のサービス利用日

上記の2つの集計結果の差が、前もって決めたしきい値より大きいかでチャーンしているかを判定するわけです。

例えば直近30日間、サービスの利用がなければチャーンしているものとみなす場合、以下のような計算でチャーンを判定します。

(そのデータの最新の日付 - 顧客ごとの最後のサービス利用日) > 30 

なお上記のしきい値は、自分達のドメイン知識をもとに自由に決めることができます。

顧客ごとの最後のサービス利用日を計算する

すでにこのデータの最新の日付の集計は終えていますので、顧客ごとの最後のサービス利用日を計算していきます。

顧客IDの列ヘッダーメニューから集計(Summarize)を選択します。

集計(Summarize)ダイアログが表示されたら、値に「timestamp」を選択し、集計関数に最後の日(max)を選択します。

列の設定から新しい列名を設定します。今回は「last_use_date」という列名に変更して、実行します。

続いて、値にデータ上の最新の日付である「last_date」を選択し、実行します。

このとき「last_date」の列には同じ値が入っているので、集計関数はデフォルトの中央値(median)のままで問題ありませんが、念のため、最後の日(max)を選択し、実行します。

これで、チャーンしているかどうかを判定するために必要な列を集計することができました。

チャーンしているかどうかを判定する

今回は直近30日間、サービスの利用がなければチャーンしているものとみなしたいので、以下の計算を実行していきます。

(そのデータの最新の日付 - 顧客ごとの最後のサービス利用日) > 30 

データ上の最後の日付の列の「last_date」の列ヘッダーメニューから計算を作成(mutate)を選択します。

計算を作成(Mutate)のダイアログが表示されたら、計算エディタに以下のようにタイプします。

(last_day - last_use_date) > 30

このとき、新しく列を作成にチェックを付けて、列名に任意の名称をつけ実行します。(今回はchurnという名前を付けています)

これで、チャーンしているかどうかを判定する列が作成できました。

サマリビューに移動すると、約40%の顧客がチャーンしているものと判定していることが分かります。

なお、このような計算方法には1つ欠点があります。

それは、設定したしきい値に明確な根拠がないということです。たまたま直近30日の利用がなかっただけで、チャーンしていると判定された人も、サービスを使い続けるかもしれません。

また人によってサービスの使い方は異なるので、毎週サービスを利用する人もいれば、そもそも2ヶ月に1度しかサービスを利用しないような人もいるわけで、そういった顧客のチャーンを的確に判定できないということがあります。

2. 顧客ごとの利用間隔からチャーンを判定する

そこで、顧客の利用パターンを考慮したうえで、チャーンを判定する方法を次に紹介します。

具体的には、顧客ごとにサービスの利用間隔の分布を見て、「この顧客からは、この日数間隔の間に、90%のケースで、次回の利用(アクセス)がある」という日数を割り出します。

この日数をサービスの利用間隔の90パーセンタイルと呼ぶのですが、顧客の最後のサービスの利用日から経過した日数が、顧客ごとの利用間隔の90パーセンタイルを越えている場合はチャーンしている、とみなすというやり方です。

(そのデータの最新の日付 - 顧客ごとの最後のサービス利用日) > 顧客ごとの利用間隔の90パーセンタイル 

なお上記のしきい値は、自分達のドメイン知識をもとに自由に決めることができます。

顧客ごとに重複する日付のデータを取り除いて、アクセス日ごとに1行のデータにする

顧客ごとの利用間隔を計算するにあたって、同じ日に複数回に渡ってサービスを利用している場合、利用間隔が0日になってしまい、顧客の利用間隔の分布の計算にあたり支障が出てしまいますので、同じ日のアクセスは1件だけ残して、それ以外は取り除きます。

今回は「顧客ごと」に利用間隔を計算したいので、データを顧客IDでグループ化します。

顧客IDごとに、アクセス日が色分けされたことが確認できます。

続いて、同じ日に複数回アクセスしている場合、1件だけを残したいので、「timestamp」の列ヘッダーメニューからフィルタ、重複する行を除くを選択します。

重複する行を除くダイアログが表示されたら、そのまま実行します。

同じアクセス日のデータを1件に絞ることができました。

利用間隔を顧客ごとに計算する

続いてサービスの利用間隔を計算します。

アクセス日でデータをソートする

まずは、利用間隔を正しく計算できるように、アクセス日でデータをソート(並べ替え)します。

「timestamp」の列ヘッダーメニューから並び替え(ソート)を選択します。

これで、顧客ごとにアクセス日でデータがソートされた状態になりました。

lag関数を使って、利用間隔を顧客ごとに計算する

この状態で、各行のアクセス日の間隔を計算することができれば、それが顧客ごとの利用間隔ということになります。

そこで1行前の値を取得することができるlag関数を利用して、利用間隔を計算します。

「timestamp」の列ヘッダーメニューから表計算(Window Calculation)を作成、…からの差、前の行の値(lag)を選択し、実行します。

続いて計算結果を数値型のデータに変換し、利用間隔の列を使ってチャーンの判定ができるようにします。

「timestamp_diff_prev」の列ヘッダーメニューから、データタイプを変換、Numeric(数値)タイプに変換、日を選択し、実行します。

顧客ごとの利用間隔の列を数値型に変換できました。

利用間隔の90パーセンタイルを顧客ごとに計算する

これで、顧客ごとに利用間隔の90パーセンタイルを集計する準備が整いました。

顧客idの列ヘッダーメニューから集計(Summarize)を選択します。

値に「timestamp_diff_prev」を選択し、集計関数に分位数(quantile)を選択します。

分位数(Quantile)に0.9(90%)を選択します。

また、新しい列名を利用間隔の90パーセンタイルに変更し、実行します。

グループ化に顧客idが選択されているので、これで顧客ごとの利用間隔の90パーセンタイルが計算されました。

顧客の最後の利用日を集計する

今回、チャーンの判定は以下のように行うので、そのデータの最新の日付と顧客ごとの最後のサービス利用日を集計しておく必要があります。

(そのデータの最新の日付 - 顧客ごとの最後のサービス利用日) > 顧客ごとの利用間隔の90パーセンタイル 

そこで、利用間隔のパーセンタイルを集計したステップのトークンをクリックします。

集計(Summarize)ダイアログが表示されたら、値に顧客のユーザーを表す「timestamp」を追加し、集計関数に最後の日(max)を選択します。

また列の設定から新しい列名を「last_use_date」に設定します。

続いて、データの最新の日付を集計するために、値に「last_day」を選択します。このとき「last_day」の列には同じ値のため、集計関数はデフォルトの中央値(median)のままでも問題ありませんが、念のため、最後の日(max)を選択し、実行します。

これで、顧客のチャーンを判定する列を集計することができました。

チャーンを判定する

以下の計算を行い、チャーンを判定していきます。

(そのデータの最新の日付 - 顧客ごとの最後のサービス利用日) > 顧客ごとの利用間隔の90パーセンタイル 

データ上の最後の日付の列である「last_day」の列ヘッダーメニューから、計算を作成(Mutate)を選択します。

計算を作成(Mutate)ダイアログが開いたら、以下の内容をタイプし実行します。

(last_day - last_use_date) > 利用間隔の90パーセンタイル

このとき、新しく列を作成にチェックを付けて、列名に任意の名称をつけ実行します。(今回はchurnという名前を付けています)

これでチャーンを判定することができました。

利用頻度が少ない顧客は、最後の利用タイミングからチャーンを判定する

ところで、今回のチャーンの判定にはサービス利用間隔の分布を利用していますが、サービスを1回しか利用したことがない顧客は、利用間隔の計算ができないため、チャーンの判定列は欠損値(<NA>)となっています。

また、サービス利用頻度が少ない顧客は、分布を見積もるためのデータが十分とは言えません。

例えば、サービスを2回しか利用したことがない顧客であれば、たった1回の利用間隔の情報からチャーンを判定していることになります。

そこで、サービスの利用頻度が少ない顧客に限っては、「最後の利用タイミングからの経過時間でチャーンを判定する」ということも可能です。

今回は、利用頻度が5回より少ない顧客は、「直近30日間、サービスの利用がなければチャーンしている」ものとして判定していきます。

顧客ごとのサービスの利用頻度を集計する

顧客の利用間隔の90パーセンタイルを集計したステップのトークンを再度クリックして開きます。

値に(行の数)を追加します。集計前のデータは1行が1アクセスを表しているので、行の数を集計すれば、利用頻度になるわけです。

列の設定アイコンをクリックして、新しい列名を「利用頻度」に設定し、実行します。

利用頻度を集計することができました。

利用頻度が少ない顧客のチャーンの判定を置き換える

続いてチャーンを判定したステップに移動します。

利用頻度の列ヘッダーメニューから、値を置き換える、条件を指定を選択します。

条件を指定して置換のダイアログが表示されたら、条件をクリックします。

すると、条件の指定ダイアログが表示されます。

今回は、利用頻度が5回より少ない顧客に限っては、「直近30日間、サービスの利用がなければチャーンしている」ものとして判定していきたいので、列に「利用頻度」、演算子により「小さい」、値に「5」を選択し、実行します。

続いて、新しい値の設定ボックスをクリックすると、新しい値の入力エディタが表示されるので、以下の内容をタイプし、OKボタンをクリックします。

(last_day - last_use_date) > 30 

これで、利用頻度が5回より少ない顧客は、直近30日間、サービスの利用がなければチャーンしていると判定できるようになりました。

利用頻度が5回以上の顧客は先程、利用間隔をもとに判定した結果を利用したいので、 それ以外の場合のボックスをクリックして、新しい値を入力に該当する列に「churn」とタイプします。

このとき、既存の列に上書きをチェックして、このまま「churn」列を上書きしても良いですが、今回はどのような差があるかを理解できるように、新しく列を作成にチェックを付けて、任意の列名を設定し、実行します。(今回は2つやり方を、合わせてチャーンを特定しているので、「churn_mix」という列名にしています。)

利用頻度が5回より少ない顧客は、「直近30日間、サービスの利用がなければチャーンしている」ものとしてチャーンを判定することができました。

これにより、チャーンの判定ができていなかった顧客のチャーンの判定ができるようになったり、サービスの利用頻度が少ない顧客のチャーンの判定が変わってきたことが分かります。

サマリビューに移動して見比べてみると、「churn_mix」には欠損値がないため、全ての顧客のチャーンを判定することができていることだけでなく、よりチャーン率が高くなっていることが分かります。

生存曲線用のデータを作る

今回チャーンを判定するために作成したデータに少し手を加えるだけで、 サービスの利用開始タイミングからのリテンション率を、経過時間ごとに可視化して、顧客のリテンションの傾向を的確に理解する生存分析という手法が試せるようになりますので、そのやり方を紹介します。

  • 参考:SaaS アナリティクス #7 - コホート分析 Part.2 - 生存曲線 - link

再度、集計したステップのトークンをクリックします。

値に「timestamp」を追加し、集計関数に最初の日(min)を選択します。

続いて列名を開始時期に変更し、実行します。

後からコホート分析をしたければ、他の列の集計もしておきます。

例えば、国の列を利用して、コホート分析がしたければ、国も集計します。値に"coutnry"を追加し、集計関数に最頻値(mode)を選択することで集計が可能です。

開始時期を集計することができました。

なお、後から顧客をサービスの利用開始タイミングごとのグループに分けて、生存曲線を比較するコホート分析をしたければ、開始時期と同じ値を持つ列をあらかじめ作成しておきます。

開始時期の列ヘッダーメニューから計算を作成(Mutate)を選択します。

新しく列を作成にチェックを付けて任意の列名を指定し実行します。(今回は「サービス開始時期」という名称を設定しています)

続いてチャーンを判定したステップに移動します。

これで生存分析やコホート分析を行うために必要な上記の情報は全て揃いました。

これらのデータを揃えれば、すぐに生存分析を始めることが可能です。

参考

  • SaaS アナリティクス #7 - コホート分析 Part.2 - 生存曲線 - リンク
  • アナリティクス:生存曲線の使い方 - リンク
  • 支払いデータから生存分析用のデータを作成する方法 - リンク
  • コンバートしてから1か月後の生存率の推移をモニターする方法 - リンク