
採用担当・発注側が本当に見たいのは、RFMで顧客を切り分け、CLV(顧客生涯価値)で投資配分を決め、キャンペーンの効果検証までを一本の物語で語れること。必要なのは巨大なDWHではなく、(1) きれいなトランザクション表、(2) 再現可能なノート/スクリプト、(3) ビジネスに直結する指標設計です。この記事はSQL+pandasだけで、RFM→セグメント施策→CLV(BG/NBD+GG)→ABテスト/増分売上を“コピペ可”で再現できるようにまとめました。
この記事で身に付く力
- RFM→CLV→ABを同じトランザクション表から通す実務フロー
- 施策に直結する図の型(ヒートマップ/箱ひげ/ウォーターフォール)と落とし穴
- 増分売上=母数×率×単価で上司に刺さる言語に翻訳する型
- そのまま使えるレポート雛形と90分アクション
関連記事:
>>実案件型ポートフォリオ:要件→実装→レポートの型|“業務再現”で採用担当に刺さる作り方
>>コピペで回るレポート納品|Jupyter→PDF/HTML→共有の自動化テンプレ
>>【保存版】pandas基礎:データフレームの作成・整形・結合・集計を“実務の型”で身につける
>>【実務で差がつく】pandas実践:欠損処理・結合・ウィンドウ関数・時系列・品質保証まで“読みやすく速い”型を習得
>>はじめてのSQL:SELECT/WHERE/GROUP BYを最短で理解【コピペOK】
>>データ可視化レポート納品の型:Tableau/Matplotlib|“図3点+結論1行+運用”で伝わる・続く・刺さる
>>コピペで動く需要予測|ARIMA×LightGBMでベースライン→運用まで
>>API入門:OpenAPI/HTTPの基本と“壊れない”Pythonクライアント設計(コピペOK)
よくあるつまずき(現場の“空振り”3つ)
四象限のRFMは作れたのに施策が出てこない/CLVモデルを作ったのに予算配分の根拠に落ちない/キャンペーンは盛り上がったが増分が言えない…この3つは頻出です。この記事ではデータ→指標→意思決定を一本線でつなぎ、各章の最後に“ビジネスの言葉”で決め切るコツを置きます。
ふみとの現場メモ
データ/マーケティングサイエンティストとして10年、100件以上の案件で効いた型は「同一のトランザクション表でRFM→CLV→ABを通す」「図は型で固定」「増分売上を“母数×率×単価”で訳す」の3つ。以下はそのまま再現できるように書いています。
データ前提:最小構成のトランザクション表
transactions(1行=1注文)に、最低限以下の列があればOKです。任意でチャネルやキャンペーンIDがあればベター。
customer_id
(文字列)order_id
(ユニーク)order_date
(日付/時刻)amount
(税込売上、返品は負)- 任意:
channel
(web/store)、campaign_id
-- 返品を控除し、顧客×日で集計(SQLite想定)
CREATE VIEW IF NOT EXISTS v_txn_daily AS
SELECT customer_id,
DATE(order_date) AS d,
SUM(amount) AS revenue,
COUNT(DISTINCT order_id) AS orders
FROM transactions
GROUP BY 1,2;
RFM:顧客の“距離×頻度×金額”を一枚に
まずは最新購入からの距離(Recency)、購入頻度(Frequency)、金額(Monetary)を集計し、五分位でスコア化。可視化は「Frequency×Monetaryのヒートマップ」「Recencyの箱ひげ」が鉄板です。
import pandas as pd
TX = pd.read\_csv("transactions.csv", parse\_dates=\["order\_date"], dtype={"customer\_id":"string"})
TX = TX.assign(d=TX\["order\_date"].dt.date)
ref = TX\["d"].max() # 参照日(最新日)
agg = TX.groupby("customer\_id").agg(
recency = ("d", lambda s: (ref - s.max()).days),
frequency = ("order\_id", "nunique"),
monetary = ("amount", "sum")
).reset\_index()
# スコア化(五分位)
for c, asc in \[("recency", True), ("frequency", False), ("monetary", False)]:
agg\[c+"\_q"] = pd.qcut(agg\[c].rank(method="first", ascending=asc), 5, labels=\[1,2,3,4,5]).astype(int)
agg\["RFM"] = agg\[\["recency\_q","frequency\_q","monetary\_q"]].astype(str).agg("".join, axis=1)
施策翻訳の例:
・555(優良)→ 定期/アップセル/先行アクセスでLTV拡大
・5x1(高R低M)→ 値引きではなく商品発見コンテンツ強化
・1x5(低R高M)→ 在庫通知/再入荷メール/限定クーポンで復帰
CLV:BG/NBD+Gamma-Gammaで“いくらまで投資できるか”
CLVは購入回数の将来予測(BG/NBD)と平均単価の予測(Gamma-Gamma)の掛け算。粗利率をかければ投資上限の目安が出ます。返品や季節性、観測期間の偏りには注意を。
# pip install lifetimes
import pandas as pd
from lifetimes.utils import summary_data_from_transaction_data
from lifetimes import BetaGeoFitter, GammaGammaFitter
TX\['date'] = pd.to\_datetime(TX\['order\_date'])
sumdata = summary\_data\_from\_transaction\_data(
TX, 'customer\_id', 'date',
monetary\_value\_col='amount',
observation\_period\_end=TX\['date'].max()
)
# 単価が0以下は除外
sumdata = sumdata\[sumdata\['monetary\_value'] > 0]
bgf = BetaGeoFitter(penalizer\_coef=0.001)
bgf.fit(sumdata\['frequency'], sumdata\['recency'], sumdata\['T'])
# 90日先の購入回数期待値
sumdata\['freq\_90'] = bgf.conditional\_expected\_number\_of\_purchases\_up\_to\_time(
90, sumdata\['frequency'], sumdata\['recency'], sumdata\['T']
)
ggf = GammaGammaFitter(penalizer\_coef=0.001)
ggf.fit(sumdata\['frequency'], sumdata\['monetary\_value'])
# 期待平均単価とCLV(粗利率=0.4の例)
sumdata\['avg\_value'] = ggf.conditional\_expected\_average\_profit(
sumdata\['frequency'], sumdata\['monetary\_value']
)
margin = 0.4
sumdata\['CLV\_90'] = sumdata\['freq\_90'] \* sumdata\['avg\_value'] \* margin
意思決定の例:
・広告の入札上限(CAC)は予測CLV×許容回収期間で決める
・CLV上位は非割引/限定アクセス、下位はコスト控えめ
キャンペーン効果:増分を“厳密に”測る
最低限の指標はCR(コンバージョン率)、AOV(平均注文額)、Revenue/Visitor。結論は「増分=Treatment−Control」と「増分売上=母数×差×単価」で示します。
import numpy as np
from statsmodels.stats.proportion import proportions_ztest
# 例:A,Bのコンバージョン
conv = np.array(\[xA, xB])
nobs = np.array(\[nA, nB])
stat, pval = proportions\_ztest(conv, nobs, alternative='larger')
# pval < 0.05 なら「BがAより有意に高い」
# CUPED(分散削減):プレ指標を共変量に使う
import numpy as np
X_pre = df['rev_pre']; Y = df['rev_exp']
theta = np.cov(Y, X_pre, bias=True)[0,1] / np.var(X_pre)
Y_adj = Y - theta * (X_pre - X_pre.mean())
# 差分の差(店舗/期間比較)
# uplift = (treat_after - treat_before) - (ctrl_after - ctrl_before)
図の型:ウォーターフォール(母数/率/単価の内訳)/ファネル(到達→閲覧→カゴ→購入)/エラーバー付き棒(CR差の95%CI)。
意思決定への落とし込み(RFM×CLV×AB)
- 誰に:RFMの555/551とCLV上位20%
- 何を:限定先行(非割引)→レビュー依頼→紹介インセン
- やめる:低CLV×高返品には値引き終了、コスト最適化
月間増分予算 = Σ セグメントi { 予測CLV_i × 到達数_i × 期待反応率_i × マージン − 配布コスト_i }
到達可能数は時系列の見立てで安全側に設定するのがコツ([内部リンク:需要予測ミニプロジェクト])。
レポート雛形(コピペ可)
# マーケティング分析サマリ(YYYY-MM-DD)
## 結論
- RFM上位2セグメント(555/551)でCLV中央値は全体比+2.1倍。今月は**限定先行×レビュー**を実施。
- キャンペーンBのCRはA比+0.8pt(p=0.03)、増分売上は**+¥12.3M**見込み。
## 根拠
* RFMヒートマップ、CLV分布、CR差分の95%CI、ウォーターフォール。
## アクション
* 上位20%へメール/アプリPUSHを**週1**、低CLV×高返品へは**値引き停止**。
* 次回は**CUPED**導入で分散削減、**A/A**で基準線更新。
業種別の“第一手”
- 小売/EC:RFM×CLVで定期/サブスク誘導、A/BはLP×配送無料で検証
- SaaS:Recencyは「最後のログイン」に置換、CLVはMRR×継続月数で
- D2C:初回→2回目の転換を重点化、サンプル/トライアルの増分を厳密に
今日やること(90分)
transactions.csv
を準備し、ビューv_txn_daily
を作成- 本記事のRFMコードで
RFM
列まで出し、ヒートマップを作る lifetimes
でCLV_90
を算出し、上位/下位の施策を1枚に- AB検定を1本回し、増分売上の式で円に翻訳
- >>コピペで回るレポート納品|Jupyter→PDF/HTML→共有の自動化テンプレの型でPDF化して配布
この記事から次に読むべきもの(内部リンク)
-
-
データ可視化レポート納品の型:Tableau/Matplotlib|“図3点+結論1行+運用”で伝わる・続く・刺さる
結論:レポートは「データ→図」ではなく「意思決定→図」の順で設計します。最短で伝わり、運用で続く“型”は、(1) 結論1行、(2) 図3点(推移・分解・構成)、(3) 打ち手(閾値/費用対効果)、(4 ...
-
-
コピペで回るレポート納品|Jupyter→PDF/HTML→共有の自動化テンプレ
毎週のレポート納品、朝にバタつきませんか? コードや図表は作ったのに、PDF化や共有で崩れる…。その“揺らぎ”を今日で終わらせましょう。 分析の価値は、最後の“納品物”で決まります。本記事では、Jup ...
-
-
【実務で差がつく】pandas実践:欠損処理・結合・ウィンドウ関数・時系列・品質保証まで“読みやすく速い”型を習得
リード(結論)基礎を終えたら次は実務の現場で頻出する処理を“型”で覚える段階です。本記事は、pandas 2.x を前提に、欠損・外れ値・結合・ウィンドウ関数・時系列・カテゴリ処理・集計の自動化・大規 ...
-
-
はじめてのSQL:SELECT/WHERE/GROUP BYを最短で理解【コピペOK】
データ分析・自動レポート・簡易アプリの土台はSQLです。Pythonだけで押し切るより、前処理の7割をDB側で完結させる方が速く・安定します。本記事は、未経験〜初学者が週10時間×2〜3週で、SELE ...
-
-
コピペで動く需要予測|ARIMA×LightGBMでベースライン→運用まで
現場でちゃんと当たる需要予測って、どこから始めればいい? ベースライン→検証→運用まで、一気通貫で進める“型”で解説します。 この記事は、ARIMAとLightGBMを使った需要予測ミニプロジェクトの ...
伴走サポート:運用まで一緒に
無料カウンセリング/体験で、データ整形→RFM→CLV→AB→レポートまで並走し、予算配分/施策停止/拡張に直結させます。
TechAcademy データサイエンスコース(受講料:174,600円~ ※更に割引あり)

株式会社キカガク AI人材長期育成コース(受講料:237,600円~)

最近のコメント