「PyMC-Marketingによる顧客のライフタイムバリュー予測」

「PyMC-Marketingによる顧客のライフタイムバリュー予測をもとにした美容とファッション業界の戦略的マーケティング」

Buy-till-You-Die(BTYD)モデリングと実践的なコーディングテクニックを探求する

UnsplashでBoxed Water Is Betterによる写真

TL; DR: 顧客生涯価値(CLV)モデルは、会社が価値のある顧客を特定するのに役立つ、顧客分析の主要な手法です。CLVを無視すると、1回の購入しかしない短期の顧客への過剰な投資につながる場合があります。BG/NBDモデルとGamma-Gammaモデルを使用した「Buy Till You Die」モデリングは、CLVを推定することができます。最良の方法はデータサイズとモデリングの優先順位によって異なりますが、PyMC-MarketingはCLVモデリングを迅速に実装するためのおすすめのPythonライブラリです。

1. CLVとは何ですか?

CLVの定義は、1つの顧客との関係を通じて企業が期待できる総純利益です。CLVとLTV(Lifeetime Value)という用語については、お馴染みの方もいらっしゃるかもしれません。はい、CLVとLTVは同義です。

著者による画像
  • 最初の目標は、将来のCLVを計算し予測することで、お客様ごとの期待される収益を把握することです。
  • 2つ目の目標は、利益を上げる顧客を特定することです。モデルによって、高いCLVを持つ顧客の特性を分析することで、価値のある顧客を特定することができます。
  • 3つ目の目標は、分析に基づいてマーケティング活動を行い、それによってマーケティング予算の配分を最適化することです。
著者による画像

2. ビジネスコンテキスト

たとえば、ナイキのようなファッションブランドのeコマースサイトでは、新規顧客を引き付けるために広告やクーポンを使用する場合があります。今、大学生と働くプロフェッショナルの2つの主要な顧客セグメントを考えてみましょう。初回購入時に、会社は大学生向けに広告に10ドル、プロフェッショナル向けに20ドルを費やしています。両セグメントとも約100ドルの購入をします。

もしマーケティングを担当していたら、どちらのセグメントにより多く投資したいですか?コストが低く、ROIが高いと考えるなら、自然と大学生セグメントにより多く投資するのが論理的だと思われるかもしれません。

著者による画像、Pixabayから使用された写真

では、もし以下の情報が分かっていたとしたらどうなるでしょうか?

大学生セグメントは離脱率が高く、1回の購入後にはもう購入しない傾向があり、平均で100ドルが使われます。一方、プロフェッショナルのセグメントはリピート購入率が高く、1人あたり平均で400ドルが入ってきます。

その場合、ROIが高いプロフェッショナルセグメントにより多く投資することを選ぶでしょう。これは、誰が長期的に利益のある顧客なのかを考慮に入れていない、大部分のマーケティング担当者がCost Per Acquisition(CPA)を重視しているが、利益のある顧客を見逃しているという単純な事実です。

著者による画像、Pixabayから使用された写真

「顧客獲得コスト」(CPA)を調整することで、より高価値の顧客を引き付け、ROIを向上させることができます。左側のグラフはCLVを考慮しないアプローチを表しています。赤い線はCPAを表しており、これは新しい顧客を獲得するために費やすことのできる最大コストです。全ての顧客に対して同じマーケティング予算を使うことは、低価値顧客への過剰投資と高価値顧客への過少投資につながります。

今度は右側のグラフは、CLVを活用した適切な支出配分を示しています。高価値顧客にはより高いCPA、低価値顧客にはより低いCPAを設定しています。

作者による画像、Pixabayから使用した写真を使用

これは採用プロセスに似ています。もし元グーグラーを雇いたいと考えるなら、競争力のある給与を提供することが重要ですよね?これにより、総マーケティング予算を変えることなく、より多くの高価値顧客を獲得することができます。

3. 必要なデータ

私が紹介するCLVモデルは、販売トランザクションデータのみを使用します。以下のように、3つのデータ列があります:customer_id、transaction date、transaction value。データ量の観点からは、CLVには通常2〜3年のトランザクションデータが必要です。

作者による画像

4. 伝統的なCLVの計算式

4.1 CLVモデリングのアプローチ

まず、CLVを計算するための2つの大きなタイプである「歴史的アプローチ」と「予測的アプローチ」を理解しましょう。予測的アプローチでは、2つのモデルがあります。「確率モデル」と「機械学習モデル」です。

作者による画像

4.2 伝統的なCLVの計算式

まずは伝統的なCLVの計算式について考えましょう。ここでは、CLVを3つの要素に分解することができます:平均注文価値、購買頻度、および顧客の寿命です。

作者による画像

例えば、ファッション会社を考えてみましょう。平均的に:

  • 顧客は注文ごとに100ドルを使います
  • 彼らは1年に4回ショッピングをします
  • 彼らは3年間忠実です

この場合、CLVは100ドル×4回×3年で計算され、顧客当たり1,200ドルとなります。この計算式は非常にシンプルで直感的ですね?しかし、いくつかの制限があります。

4.3 伝統的なCLVの計算式の制限

作者による画像

制限1:すべての顧客が同じではない

この伝統的な計算式では、すべての顧客が同質であり、平均数値が全ての顧客の特性を表すと仮定しています。しかし、一部の顧客が非常に大きな購入をする場合、平均値は全ての顧客の特徴を表しているわけではありません。

制限2:最初の購入のタイミングの違い

例えば、データ収集期間として過去12ヶ月を使用するとします。

作者による画像、Pixabayから使用した写真を使用

この男性は約1年前に初めて購入をしました。この場合、年間の購入頻度を正確に計算することができます。それは8です。

では2人の顧客はどうでしょうか?一人は6ヶ月前に購入を始め、もう一人は3ヶ月前から始めました。みんな同じペースで買い物をしています。しかし、過去1年間の総購入数を見ると、異なっています。ここで重要なポイントは、顧客の所属期間、つまり最初の購入からの経過時間を考慮する必要があるということです。

制限事項3:生存か死か?

顧客が「離反」と見なされる時期を判断するのは難しいです。Netflixのような定額制のサービスでは、顧客が退会すれば離反と見なすことができます。しかし、小売業やEコマースの場合、顧客が「生存」なのか「非生存」なのかは曖昧です。

顧客の「生存の可能性」は過去の購入パターンに依存します。たとえば、普段毎月買い物をする人が次の3ヶ月間購入しない場合、別のブランドに乗り換えるかもしれません。ただし、通常6ヶ月に1度しか買い物しない人が次の3ヶ月間何も買わない場合は心配する必要はありません。

作者によるイメージ、写真はPixabayから使用

5. Buy-Till-You-Die(BTYD) モデル

これらの課題に対応するために、私たちはしばしば「Buy Till You Die」(BTYD)モデリングを活用します。このアプローチには2つのサブモデルが含まれます:

  1. BG-NBDモデル:これは顧客のアクティブな状態と取引頻度の可能性を予測します。

2. ガンマ・ガンマモデル:これは平均注文価値を推定します。

これらのサブモデルの結果を組み合わせることで、顧客の生涯価値(CLV)を効果的に予測することができます。

作者によるイメージ

5.1 BG/NBDモデル

私たちは、顧客の状態には2つのプロセスがあると考えています。購入プロセスでは、顧客が積極的に購入しています。ドロップアウトプロセスでは、顧客が購入を停止しました。

アクティブな購買フェーズでは、モデルは「ポアソン過程」を使って顧客の購入頻度を予測します。

顧客が購入後にいつでも離脱する可能性があります。BG/NBDモデルは、この可能性に確率「p」を割り当てます。

イメージを参考にしてください。データはこの顧客が5回購入したことを示しています。しかし、仮定によると、この顧客がアクティブであった場合、総計で8回の購入を行ったでしょう。しかし、ある時点で生存の確率が低下したため、実際の購入回数は5回しか見えません。

作者によるイメージ

購入頻度は「アクティブ」の状態ではポアソン過程に従います。ポアソン分布は通常、ランダムに発生するイベントの数を表します。ここでは、「λ」が各顧客の購入頻度を示しています。ただし、顧客の購入頻度は変動する場合があります。ポアソン分布は、購入頻度の変動性を考慮します。

作者によるイメージ;グラフはWikipediaから引用

以下のグラフは、時間の経過とともに「p」がどのように変化するかを示しています。最後の購入からの経過時間が増えるにつれて(T=31)、顧客が「生存」と見なされる確率が低下します。再購入が発生すると(T=36付近)、再び「p」が増加することに気付くでしょう。

著者による画像

これはグラフィカルモデルです。先ほど説明したように、λとpが含まれています。ここでは、λとpは人によって異なります。この多様性を考慮するために、λの異質性はガンマ分布に従い、pの異質性はベータ分布に従うものと仮定します。言い換えれば、このモデルはBayesの定理に基づく階層的なアプローチを使用しています。

著者による画像

5.2 ガンマ-ガンマモデル

平均注文額はガンマ分布でモデル化されると仮定します。ガンマ分布は、形状パラメータとスケールパラメータで形成されます。このグラフが示すように、これらの2つのパラメータを変更することでガンマ分布の形状がかなり変わることがあります。

著者による画像;グラフはWikipediaから引用

この図は使用されるグラフィカルモデルを示しています。このモデルは、ベイズの階層的なアプローチを使用して2つのガンマ分布を採用しています。最初のガンマ分布は、各顧客の「平均注文額」を表します。この値は顧客によって異なるため、2番目のガンマ分布は顧客全体の平均注文額の変動を捉えます。事前分布のパラメータp、q、γはHalf-flat priorsを使用して決定されます。

著者による画像

6. サンプルコード

役立つCLVライブラリ

ここでは、CLVモデリングに役立つ2つの優れたOSSライブラリを紹介します。最初のライブラリはPyMC-Marketingで、2番目のライブラリはCLVToolsです。両方のライブラリは「買い物を止めるまで」モデリングを取り入れています。最も重要な違いは、PyMC-MarketingがPythonベースのライブラリであるのに対し、CLVToolsはRベースです。PyMC-Marketingは、人気のあるベイズライブラリであるPyMCをベースに構築されています。以前は「Lifetimes」というよく知られたライブラリがありました。しかし、「Lifetimes」は現在メンテナンスモードに移行しているため、PyMC-Marketingに移行しました。

フルコード

フルコードは以下のGithubで見つけることができます。私のサンプルコードはPyMC-Marketingの公式クイックスタートをベースにしています。

GitHub – takechanman1228/Effective-CLV-Modeling

GitHubへの貢献 – takechanman1228/Effectiv

データクレンジング

迅速なデータクレンジングが必要です。たとえば、返品注文を処理し、顧客IDのないレコードをフィルタリングし、数量と単価を掛け合わせることで「総売上」の列を作成する必要があります。

# 返品注文の処理# 'InvoiceNo'が"C"で始まる行を抽出するcancelled_orders = data_raw[data_raw['InvoiceNo'].astype(str).str.startswith("C")]# マッチングしたい列で一時的なDataFrameを作成し、また'Quantity'列を否定するcancelled_orders['Quantity'] = -cancelled_orders['Quantity']# マッチングしたい列を指定して元のDataFrameと一時的なDataFrameをマージするmerged_data = pd.merge(data_raw, cancelled_orders[['CustomerID', 'StockCode', 'Quantity', 'UnitPrice']],                        on=['CustomerID', 'StockCode', 'Quantity', 'UnitPrice'],                        how='left', indicator=True)# マッチングした行をフィルタリングし、元の返品注文もフィルタリングするdata_raw = merged_data[(merged_data['_merge'] == 'left_only') & (~merged_data['InvoiceNo'].astype(str).str.startswith("C"))]# インジケーター列を削除するdata_raw = data_raw.drop(columns=['_merge'])# 関連する特徴を選択し、総売上を計算するfeatures = ['CustomerID', 'InvoiceNo', 'InvoiceDate', 'Quantity', 'UnitPrice', 'Country']data = data_raw[features]data['TotalSales'] = data['Quantity'].multiply(data['UnitPrice'])# 個々の顧客の行動に寄与しないため、顧客IDが欠落した取引を削除するdata = data[data['CustomerID'].notna()]data['CustomerID'] = data['CustomerID'].astype(int).astype(str)data.head()
Image by Author

次に、この「clv_summary」関数を使用してサマリーテーブルを作成する必要があります。この関数は、RFM-T形式のデータフレームを返します。RFM-Tとは、Recency(最近の購入)、 Frequency(頻度)、 Monetary(金銭的価値)、およびTenure(顧客継続期間)を意味します。これらのメトリクスは、ショッパー分析でよく使用されます。

data_summary_rfm = clv.utils.clv_summary(data, 'CustomerID', 'InvoiceDate', 'TotalSales')data_summary_rfm = data_summary_rfm.rename(columns={'CustomerID': 'customer_id'})data_summary_rfm.index = data_summary_rfm['customer_id']data_summary_rfm.head()

BG/NBDモデル

BG/NBDモデルは、このライブラリのBetaGeoModel関数として利用できます。bgm.fit()を実行すると、モデルのトレーニングが開始されます。

bgm.fit_summary()を実行すると、学習プロセスの統計的サマリーが表示されます。たとえば、この表は、パラメータの平均、標準偏差、ハイデンシティインターバル(HDI)などを示しています。マルコフ連鎖モンテカルロ(MCMC)シミュレーションが収束したかどうかを評価するために、r_hat値を確認することもできます。R-hatは1.1以下であれば受け入れ可能とされています。

bgm = clv.BetaGeoModel(    data = data_summary_rfm,)bgm.build_model()bgm.fit()bgm.fit_summary()

以下の行列は「確率生存行列」と呼ばれます。これを使用することで、再購入が予測されるユーザーと予測されないユーザーを推定できます。X軸は顧客の過去の購入頻度を、y軸は顧客の最近性を表しています。色は生存確率を示しています。新しい顧客は左下のコーナーにいます:低頻度で高最近性です。これらの顧客は生存確率が高いです。忠誠な顧客は右下にいます:高頻度で高最近性の顧客です。一定期間購入しない場合、忠誠な顧客はリスク顧客となり、生存確率が低くなります。

clv.plot_probability_alive_matrix(bgm);
Image by Author

次に、各顧客の将来の取引を予測することができます。 expected_num_purchases 関数を使用することができます。モデルをフィットさせた後、次の期間での予想購入数は何ですかと尋ねることができます。

num_purchases = bgm.expected_num_purchases(    customer_id=data_summary_rfm["customer_id"],    t=365,    frequency=data_summary_rfm["frequency"],    recency=data_summary_rfm["recency"],    T=data_summary_rfm["T"])sdata = data_summary_rfm.copy()sdata["expected_purchases"] = num_purchases.mean(("chain", "draw")).valuessdata.sort_values(by="expected_purchases").tail(4)

ガンマガンマモデル

次に、ガンマガンマモデルに移行して平均注文価格を予測します。 ‘Expected_customer_spend’ 関数を使用して、予想される「平均注文価格」を予測することができます。

nonzero_data = data_summary_rfm.query("frequency>0")dataset = pd.DataFrame({    'customer_id': nonzero_data.customer_id,    'mean_transaction_value': nonzero_data["monetary_value"],    'frequency': nonzero_data["frequency"],})gg = clv.GammaGammaModel(    data = dataset)gg.build_model()gg.fit();expected_spend = gg.expected_customer_spend(    customer_id=data_summary_rfm["customer_id"],    mean_transaction_value=data_summary_rfm["monetary_value"],    frequency=data_summary_rfm["frequency"],)

以下のグラフは、5人の顧客の予想される平均注文価値を示しています。これら2人の顧客の平均注文価値は500ドル以上で、これら3人の顧客の平均注文価値は約350ドルです。

labeller = MapLabeller(var_name_map={"x": "customer"})az.plot_forest(expected_spend.isel(customer_id=(range(5))), combined=True, labeller=labeller)plt.xlabel("予想される平均注文価値");
Image by Author

結果

最後に、2つのサブモデルを組み合わせて各顧客のCLVを推定することができます。ここで言及したい1つのことは、パラメータ「Discount_rate」です。この関数はDCFメソッド(割引現金フロー)を使用します。月次の割引率が1%の場合、1ヶ月での100ドルの価値は今日の99ドルの価値です。

clv_estimate = gg.expected_customer_lifetime_value(    transaction_model=bgm,    customer_id=data_summary_rfm['customer_id'],    mean_transaction_value=data_summary_rfm["monetary_value"],    frequency=data_summary_rfm["frequency"],    recency=data_summary_rfm["recency"],    T=data_summary_rfm["T"],    time=120, # 120ヶ月=10年    discount_rate=0.01,    freq="D",)clv_df = az.summary(clv_estimate, kind="stats").reset_index()clv_df['customer_id'] = clv_df['index'].str.extract('(\d+)')[0]clv_df = clv_df[['customer_id', 'mean', 'hdi_3%', 'hdi_97%']]clv_df.rename(columns={'mean' : 'clv_estimate', 'hdi_3%': 'clv_estimate_hdi_3%', 'hdi_97%': 'clv_estimate_hdi_97%'}, inplace=True)# monetary_values = data_summary_rfm.loc[clv_df['customer_id'], 'monetary_value']monetary_values = data_summary_rfm.set_index('customer_id').loc[clv_df['customer_id'], 'monetary_value']clv_df['monetary_value'] = monetary_values.valuesclv_df.to_csv('clv_estimates_output.csv', index=False)

今、私たちはマーケティングアクションの改善方法について紹介します。以下のグラフは、国別の推定CLVを示しています。

# 1トランザクションあたりの総売上高を計算するdata['TotalSales'] = data['Quantity'] * data['UnitPrice']customer_sales = data.groupby('CustomerID').agg({    'TotalSales': sum,    'Country': 'first'  # 顧客が1つの国に関連付けられていると仮定})customer_countries = customer_sales.reset_index()[['CustomerID', 'Country']]clv_with_country = pd.merge(clv_df, customer_countries, left_on='customer_id', right_on='CustomerID', how='left')average_clv_by_country = clv_with_country.groupby('Country')['clv_estimate'].mean()customer_count_by_country = data.groupby('Country')['CustomerID'].nunique()country_clv_summary = pd.DataFrame({    'AverageCLV': average_clv_by_country,    'CustomerCount': customer_count_by_country,})# 各国のCLVの推定値の平均値を計算するaverage_clv_lower_by_country = clv_with_country.groupby('Country')['clv_estimate_hdi_3%'].mean()average_clv_upper_by_country = clv_with_country.groupby('Country')['clv_estimate_hdi_97%'].mean()# これらの平均値をcountry_clv_summaryデータフレームに追加するcountry_clv_summary['AverageCLVLower'] = average_clv_lower_by_countrycountry_clv_summary['AverageCLVUpper'] = average_clv_upper_by_country# 顧客数が20以上の国をフィルタリングするfiltered_countries = country_clv_summary[country_clv_summary['CustomerCount'] >= 20]# CustomerCountで降順にソートするsorted_countries = filtered_countries.sort_values(by='AverageCLV', ascending=False)# 誤差棒の準備lower_error = sorted_countries['AverageCLV'] - sorted_countries['AverageCLVLower']upper_error = sorted_countries['AverageCLVUpper'] - sorted_countries['AverageCLV']asymmetric_error = [lower_error, upper_error]# 固定サイズの新しいグラフを作成するplt.figure(figsize=(12,8))# 平均CLVを表すプロットを作成し、信頼区間を示すエラーバーを加えるplt.errorbar(x=sorted_countries['AverageCLV'], y=sorted_countries.index.tolist(),              xerr=asymmetric_error, fmt='o', color='black', ecolor='lightgray', capsize=5, markeredgewidth=2)# ラベルとタイトルを設定するplt.xlabel('平均CLV')  # x軸のラベルplt.ylabel('国')  # y軸のラベルplt.title('国別の平均顧客生涯価値(CLV)と信頼区間')  # グラフのタイトル# y軸を上から下に表示するように調整するplt.gca().invert_yaxis()# グリッド線を表示するplt.grid(True, linestyle='--', alpha=0.7)# グラフを表示するplt.show()
Image by Author

フランスの顧客はCLVが高くなりがちです。一方、ベルギーの顧客はCLVが低くなりがちです。この結果から、フランスの顧客を獲得するためのマーケティング予算を増やし、ベルギーの顧客を獲得するためのマーケティング予算を削減することをおすすめします。米国のデータを使用してモデリングを行う場合、国の代わりに州を使用します。

7. モデルの正確性を向上させるにはどうすればいいですか?

おそらく疑問に思っているかもしれません:

  • アクセスログなどの追加のデータを利用することはできますか?
  • 人口統計情報やマーケティング活動など、他の特徴量をモデルに組み込むことは可能ですか?

基本的に、BTYDモデルはトランザクションデータのみを必要とします。他のデータや特徴量を使用する場合は、MLアプローチが選択肢になります。その後、ベイジアンモデルとMLモデルの性能を評価し、より正確性と解釈性の高いものを選択することができます。

以下のフローチャートは、より良いCLVモデリングのためのガイドラインを示しています。

Image by Author

まず、データのサイズを考慮してください。データが十分に大きくない場合やトランザクションデータしかない場合、PyMC Marketingを使用したBTYDモデリングが最適な選択肢となります。データが十分に大きい場合でも、BTYDモデルで十分な性能が得られない場合は異なるアプローチを試すことが良いでしょう。特に精度が解釈性よりも重視される場合、ニューラルネットワーク、XGboost、LightGBM、アンサンブル技術などが有益です。解釈性がまだ重要な場合は、ランダムフォレストや可解釈性AIアプローチなどの方法を検討してください。

まとめると、どの場合でも、私はPyMCマーケティングを始めることをお勧めします!

8. 結論

以下がいくつかの重要なポイントです。

  • 顧客生涯価値(CLV)とは、企業が顧客との関係を通じて期待できる総純利益のことです。
  • BG/NBDモデルとガンマ・ガンマモデルを使用して確率的モデル(BTYD)を構築することができます。
  • Pythonに慣れている場合は、PyMC-Marketingが始めることができる場所です。

お読みいただきありがとうございます!ご質問や提案がある場合は、Linkedinでお気軽にご連絡ください!また、Towards Data Scienceで私をフォローしていただけると嬉しいです。

9. 参考文献

We will continue to update VoAGI; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more