MMM(マーケティングミックスモデリング)ツール「Robyn」の使い方
MetaのMMMツール「Robyn」の使い方を備忘録として残しておきます。
全体概要
まず、Robynは大まかに次のような関数を使って実行していきます。
各それぞれの関数の内容を大まかに説明しておきます。
関数名 | 内容 |
---|---|
robyn_inputs() |
入力データ(広告費、売上、外部要因など)やモデル構築の設定を準備する関数。Robynの分析に必要なデータを整える。 |
robyn_run() |
準備したデータを基にモデルを構築し、各広告の効果や寄与度を算出する関数。複数のハイパーパラメータを試行して最適なモデルを探索する。 |
robyn_outputs() |
モデル構築の結果を整理し、パレート最適なモデルや各モデルの指標(ROAS、NRMSEなど)を出力する関数。結果の全体像を確認する。 |
robyn_write() |
選択したモデルを保存し、後で再利用可能な状態にする関数。リフレッシュや他のプロジェクトで使うためのエクスポート用。 |
robyn_onepagers() |
選択したモデルの詳細なレポート(One-pager)を生成し、各広告の貢献度や予算配分を可視化する関数。 |
robyn_allocator() |
広告予算を各チャネルに最適に配分するための計算を実行。目標(売上やレスポンス)の最大化やROIの最適化を行う。 |
robyn_save() |
モデルの途中結果や最終結果を保存し、複数のシナリオを比較できるようにする関数。 |
robyn_refresh() |
既存のモデルを新しいデータに基づいてアップデートし、最新の状況を反映した分析を行う関数。※2025年1月25日現在は詳細を記述していません。 |
Step 0|Robynのインストールと実行準備
まずは、Robyn
とreticulate
をCRANからインストールします。
Robynはモデリングの際にNevergra
という最適化のソルバーを使用します。このNevergra
はPythonを使用したソルバーであるため、RからPythonを使えるようにreticulate
というパッケージもインストールしておきます。
そして一旦、packageVersion("Robyn")
でRobynのバージョンを確認してみます。
※2025年1月25日現在でver3.11.1でした。
#### Step 0: 環境設定
## マルチコアで計算を行う設定(MacやLinuxなどのUnix系システムの場合)
# (基本的にはRobyn内で勝手にやってくれるが、明示的に設定することでエラー回避につながる)
library(future)
Sys.setenv(R_FUTURE_FORK_ENABLE = "TRUE")#毎回実行
options(future.fork.enable = TRUE)#毎回実行
plan(multisession) # RStudioでも安全な並列処理
# 必要なパッケージのインストール(初回のみ実行)
# Robyn: MMM用
# reticulate: Pythonとの連携用
install.packages("Robyn")
install.packages("reticulate")
# ライブラリの読み込み
library(Robyn)
library(reticulate)
# Robynのバージョン確認
packageVersion("Robyn")
続いて、Pythonの環境を設定していきます。
Pythonの環境を用意する方法としては、conda
を使う方法とvirtualenv
を使用する方法がありますが、今回はconda
を使っていきます。
# minicondaを使ってPythonの設定を行う
install_miniconda()
conda_create("r-reticulate")
use_condaenv("r-reticulate")
#仮想環境の確認
py_config()
Pythonの仮想環境の準備が終わったらいよいよRobynの準備も次が最後です。
## Robynの使用準備
create_files <- TRUE
robyn_directory <- "~/MMM"
Step 1|データの読み込み
今回の入力データは、筆者がこの記事用に作成したデータを用います。人工的に作成した広告の投下費用や売上などから構成される日次の時系列データです。
変数 | 概要 |
---|---|
Date | "YYYY-MM-DD"の形式の日時データ |
Net_Ad_Spend | 1日あたりのネット広告出稿金額 |
TV_Ad_Spend | 1日あたりのTV広告出稿金額 |
Avg_Temp | その日の平均気温 |
Rainfall | その日の降水量 |
Revenue | その日の売上金額 |
Weekend_Flag | 週末であるならば1それ以外なら0の変数 |
それでは実際にデータを読み込んでいきます。
#### Step 1: データの読み込み
library(data.table) # fread関数を使用するためのパッケージを呼び出す
data <- fread("sample.csv") # データの読み込み
# 試しに動かしてみたい方は同じサンプルデータを用意しているのでこちらからどうぞ↓
# library(readr)
# data <- read_delim("https://github.com/TakashiNotomi/MMM-train/blob/main/sample.csv")
head(data) # 読み込んだデータの先頭部分を確認
str(data) # データ形式を確認
ちなみに、データを読み込む際にfread
関数を使っていますが、read_csv
やread.csv
関数等お好きなものを使っていただいて構いません。個人的に割と大きめなデータを読み込むのが早くて使い勝手が良いのでfread
関数を使っています。
head()
関数やstr()
関数でdata
の中身を確認して、数値データが文字列として扱われたりしていないかの確認を行います。
Step 2|モデルの入力変数指定
次に入力データ(sample.csv
)がどういったものなのかをrobyn_inputs()
関数を使って設定します。主に以下の設定を行います。
変数 | 今回の設定 | 説明 |
---|---|---|
dt_input |
data |
分析に使用するデータを指定します |
dt_holidays |
dt_prophet_holidays |
祝日データ |
date_var |
"date" |
日付変数の列名 |
dep_var |
"Revenue" |
売上変数の列名 |
dep_var_type |
"revenue" |
目的変数が売上高なのかCVなのか(revenue もしくはconversion のいずれかを選択) |
prophet_vars |
c("trend", "season", "weekend", "holiday") |
時系列の要素に関する各影響を考慮するか否か。"trend" : 長期的なトレンド、"season" : 季節性(毎年のパターン)、"weekday" : 曜日ごとの影響、"holidays" : 祝日による影響。 |
prophet_country |
"JP" |
祝日データを参照する国名(JP は日本を指しています) |
context_vars |
c("temperature", "rain", "Weekend_Flag") |
イベントに関する変数の列名 |
paid_media_spends |
c("Net_Ad_Spend", "TV_Ad_Spend") |
メディア支出の名称 |
paid_media_vars |
c("Net_Ad_Spend", "TV_Ad_Spend") |
メディア支出に関する変数の列名 |
organic_vars |
c("newsletter") |
PRなどの非広告メディアの変数 |
factor_vars |
c("Weekend_Flag") |
イベント(※要修正) |
factor_sign |
※要修正 | ※要修正 |
window_start |
"2019-04-01" |
モデル構築に使用するデータの開始日 |
window_end |
"2020-03-31" |
モデル構築に使用するデータの終了日 |
hyperparameters |
※要修正 | 長くなるので後ほど詳細を記述 |
adstock |
"geometric" |
Adstock効果の形状( weibull_cdf や weibull_pdf でもOK) |
では実際にrobyn_inputs()
関数を使って、先ほどの引数を入力していきたいと思います。
入力変数の指定
#### Step 2a: 初回ユーザ向けモデル仕様設定
#### 2a-1: 入力変数の指定
# 入力データを設定
InputCollect <- robyn_inputs(
dt_input = data, # 分析対象データ
dt_holidays = dt_prophet_holidays, # 祝日データ(Robynには事前に`dt_prophet_holidays`の中に世界各国の祝日データが含まれています)
date_var = "datetime", # 日付変数(例: "2025-01-01")
dep_var = "Revenue", # 目的変数("revenue"もしくは"conversion")
dep_var_type = "revenue", # 目的変数("revenue"もしくは"conversion")
prophet_vars = c("trend", "season", "weekday", "holiday"), # 時系列要素を考慮するか否か
prophet_country = "JP", # 祝日データを参照する国名(日本は"JP")
context_vars = c("Avg_Temp", "Rainfall", "Weekend_Flag"), # イベント情報
paid_media_spends = c("Net.Spend", "Tv.Spend"), # 広告費用
paid_media_vars = c("Net.Spend", "Tv.Spend"), # 広告効果指標(PV等を入力。なければ広告費用と同様のものを入力。)
# organic_vars = c("newsletter", "SNS"), # SNSなどの費用がかからないメディア(今回はデータに非広告メディアが存在しないので不要)
factor_vars = c("Weekend_Flag"), # context_varsのうち、カテゴリ変数(0,1で表現)のもの
window_start = "2018-01-01", # モデル構築に使用するデータの開始日
window_end = "2018-12-31", # モデル構築に使用するデータの終了日
adstock = "geometric" # Adstock効果の形状
)
print(InputCollect)
ここまで実行すると以下のように出力されます。
> print(InputCollect)
Total Observations: 365 (days)
Input Table Columns (7):
Date: Date
Dependent: Revenue [revenue]
Paid Media: Net_Ad_Spend, TV_Ad_Spend
Paid Media Spend: Net_Ad_Spend, TV_Ad_Spend
Context: Avg_Temp, Rainfall, Weekend_Flag
Organic:
Prophet (Auto-generated): trend, season, weekday, holiday on JP
Unused variables: None
Date Range: 2023-01-01:2023-12-31
Model Window: 2023-01-01:2023-12-31 (365 days)
With Calibration: FALSE
Custom parameters: None
Adstock: geometric
Hyper-parameters: Not set yet
ハイパーパラメータ(Hyper-parameters)がまだ設定されていないと出力されていますが、ここはかなり細かく設定できるので、以下で別途指定するようにします。(もちろん上にまとめてしまってもいいですが複雑な形になるのであまりおすすめしません)
ハイパーパラメータとは
ハイパーパラメータとは、モデルのパラメータを制御する上位のパラメータ。すなわちパラメータのパラメータのことを指します。
ハイパーパラメータの設定
まずハイパーパラメータでは以下のようなことを設定します。
- 広告効果の飽和を制御(saturation)
- 広告効果の減衰を制御(adstock)
- トレーニングデータの割合(train_size)
広告効果の飽和(頭打ち)を制御するパラメータ(saturation)と、広告効果の減衰を制御するパラメータ(adstock)と呼ばれる2つがあります。前者のsaturationの形状はalpha
とgamma
で指定します。後者のadstockの形状は幾何学(geometric
)型がtheta
、ワイブル型がscale
とshape
というパラメータを持ちます。
#### 2a-2: ハイパーパラメータの定義
# 使用するハイパーパラメータの表示
hyper_names(adstock = InputCollect$adstock, all_media = InputCollect$all_media)
# Adstockと飽和曲線の形状を確認(必要に応じてプロットを表示)
plot_adstock(plot = FALSE)
plot_saturation(plot = FALSE)
# ハイパーパラメータの可変領域を設定
hyperparameters <- list(
Net.Spend_alphas = c(0.5, 3),
Net.Spend_gammas = c(0.3, 1),
Net.Spend_thetas = c(0, 0.3),
Tv.Spend_alphas = c(0.5, 3),
Tv.Spend_gammas = c(0.3, 1),
Tv.Spend_thetas = c(0.1, 0.4),
train_size = 0.7 # トレーニングデータの割合
)
上記のようにハイパーパラメータを指定することができたら、先ほど作成したrobyn_inputs
を上書きしていきます。
ハイパーパラメータをrobyn_inputsに入力
#### 2a-3: ハイパーパラメータをrobyn_inputsに入力
# ハイパーパラメータを含むInputCollectオブジェクトを更新
InputCollect <- robyn_inputs(InputCollect = InputCollect, hyperparameters = hyperparameters)
print(InputCollect)
そしてハイパーパラメータの設定が終わったらもう一度形状を確認しておきます。
plot_adstock(plot = TRUE)
plot_saturation(plot = TRUE)
Step 3|モデルの構築
モデルの構築を行なっていきます。
まずは先ほどのハイパーパラメータの中から最適な組み合わせを探索します。その探索の試行回数をiteration=2000
と指定しています。
また、同じ設定でモデルを複数回試行し、最適なモデルを見つけるために、trials=5
としています。これは「異なる初期条件やランダムな組み合わせで探索を繰り返す回数」を指定します。
またts_validation = TRUE
とすることで、①トレーニング、②テスト、③検証の3つのデータに分割され、オーバーフィッティングを回避しより精度の高いモデルが作れるようになります。
#### Step 3: 初期モデルの構築
# モデルの全試行とイテレーションを実行
set.seed(123) # 再現性を担保
OutputModels <- robyn_run(
InputCollect = InputCollect, # モデル仕様を全て入力
cores = NULL, # 並列計算を行う場合、使用するCPUコア数を指定(デフォルトではそのPCの最大CPUコア数-1で処理するようになっている)
iterations = 2000, # 推奨: 2000回(ダミーデータセットに対して)
trials = 5, # 推奨: 5回(ダミーデータセットに対して)
ts_validation = TRUE, # NRMSEを基準にクロスバリデーションを実施
add_penalty_factor = FALSE # 広告チャネルの貢献度やROASを調整するためのペナルティを有効化するかどうかを指定するパラメータ
)
print(OutputModels)
上記のスクリプトでは、Metaの勾配フリー最適化プラットフォームNevergrad
を使ってパラメータの最適化を行います。最適化は目的関数を最小化するのですが、Robynの最適化の目的関数として以下の3つが与えられています。
-
NRMSE
正規化平均2乗誤差で、予測誤差とも呼ばれています。 -
DECOMP.RSSD
Robynで注目すべき目的関数。分散2乗距離の平方根で、ビジネス誤差とも呼ばれています。これは有料メディアの支出シェアと効果シェアの差を表します。これはまた別の記事で詳細を書こうと思います。 -
MAPE.LIFT
Robynで算出した予測値に対する実測値との誤差のこと。有効になるリフトテストの平均絶対パーセンテージ誤差で、キャリブレーション誤差とも呼ばれます。
上記の目的関数に対して、パレート最適化の概念を使用して、最適なモデル候補のセットを出力します。
パレート最適化とは
複数の評価指標を同時に最適化した解で、どちらかを改善しようとすると他方が悪化するような状態を指します。
下記のスクリプトは、パレート最適化を図示するものです。
# 収束状況をplot
OutputModels$convergence$moo_cloud_plot
OutputModels$convergence$moo_distrb_plot
# クロスバリデーションplot
if (OutputModels$ts_validation) OutputModels$ts_validation_plot
上の図は、チャート内の各点が探索された解を表します。2つの軸(横軸がNRMSE、縦軸がDECOMP.RSSD)は最小化されるべき2つの目的関数であり、反復回数が増えるにつれて上図の左下方向に向かう傾向が見られます。これはNevergrad
がモデル結果を最適な方向に導いている証拠です。
また、Robynにおけるモデルの収束とは、以下の2つの条件を満たした場合を指します。
- 最後の四分位範囲の標準偏差が最初の3つの四分位範囲の標準偏差の平均より小さいこと。
- 最後の四分位範囲の絶対中央値が最初の四分位範囲の絶対中央値-最初の3つの四分位範囲の標準偏差の平均*2よりも小さいこと。
下の図は、この収束していく様子を可視化したものに該当します。
さらに、クロスバリデーションによる誤差の確認も行います。
試行回数が増えるごとに収束していっている様子が上図より確認できます。
モデルが収束していることを確認できたら、パレート最適解の抽出をrobyn_outputs()
関数を用いて行います。まずは関数の各パラメータを紹介します。
変数 | 今回の設定 | 説明 |
---|---|---|
InputCollect |
InputCollect |
- |
OutputModels |
OutputModels |
- |
pareto_fonts |
"auto" |
パレート最適解としてどれくらいの層のモデル群を取得するか具体的な数値で指定可能。1 とした場合パレート最適の最良の1層を取得。基本的には"auto" を選択しておけば良い。 |
calibration_constraint |
- | 今回はキャリブレーションデータ(過去施策の実績等データ)が存在しないため設定不要。 |
plot_folder |
robyn_director |
結果をアウトプットするのフォルダ |
plot_folder_sub |
- | 上記のフォルダのサブフォルダとして使えるもの |
plot_pareto |
create_files |
パレート最適解の結果を保存するか否か。フォルダ名を指定した場合指定フォルダにモデルごとのプロットが保存される。 |
csv_out |
"pareto" |
csvに出力するか否か。"pareto" を指定した場合は、先ほど"pareto" で指定した分だけがcsvとして出力される。"all" を指定することもできる。 |
clusters |
TRUE |
パレート最適解のモデルをクラスタリングするかどうか。デフォルトでTRUE なので、FALSE を選択したい場合にこちらのパラメータを用いると良い。 |
上記を実際にスクリプトにしたものが下になります。
## パレート最適解の抽出、結果とplotを指定フォルダにエクスポート
OutputCollect <- robyn_outputs(
InputCollect, OutputModels,
pareto_fronts = "auto", # パレートフロントの数を指定(基本的には"auto"としておけば問題ない)
csv_out = "pareto", # csv出力するモデルを選択("pareto", "all", もしくは NULL )
clusters = TRUE, # パレート最適解のモデルをROASに基づいてクラスタリングするか
export = create_files, # プロットやモデル情報をローカルフォルダに保存するか
plot_folder = robyn_directory, # 指定したフォルダ内に結果を保存
plot_pareto = create_files # パレート最適解のプロット(One pager)を作成して保存するかどうかを指定
)
print(OutputCollect)
これらを実行すると、ファイルに保存されます。
クラスタリング結果などなど複数ファイルが出力されるのですが、主に見ていただきたいのが以下のように出力された8つの結果がまとめられた画像です。
①左上: ウォーターフォール図
詳細はこちら
説明 | 概要 |
---|---|
内容 | 成果変数(例: 売上)への全体寄与を1としたとき、各要素(メディアチャネル、ベースライン、季節要因など)の寄与割合を示します。 |
目的 | どの変数がどれだけ成果に寄与したかを一目で理解するため。 |
解釈例 | ベースラインが63%、ネット広告が3.1%、テレビ広告が9.2%寄与。ベースラインはコントロールできない要因(季節、トレンドなど)を示します。 |
②右上: 時系列折れ線グラフ
詳細はこちら
説明 | 概要 |
---|---|
内容 | 実際の成果変数の値(例: 売上)とモデルが予測した値を比較したプロット。 |
目的 | モデルがどれだけ実際のデータに適合しているか(フィット精度)を確認するため。 |
特徴 | データは train , valid , test に分かれて表示。外れ値やモデルがキャッチできなかった特別なイベントも発見可能。 |
解釈例 | R²が高い場合、実績値と予測値が近似している。 |
③左上から2番目: 横棒グラフとROIの折れ線グラフ
詳細はこちら
説明 | 概要 |
---|---|
内容 | メディアごとの支出シェア(広告費の割合)と効果シェア(成果変数への寄与の割合)を比較するプロット。 |
目的 | 各メディアの費用対効果を確認し、広告配分の適切性を評価するため。 |
補足 | 支出シェア: 各広告チャネルの予算配分割合。効果シェア: 売上や成果における寄与割合。ROAS(広告費用対効果)も合わせて確認可能。 |
解釈例 | 支出シェアが低いが効果シェアが高いチャネルは効率的。 |
④右上から2番目: ROIの信頼区間
詳細はこちら
説明 | 概要 |
---|---|
内容 | ブートストラップ法に基づいて算出したROI(Return on Investment)の信頼区間をプロット。 |
目的 | 広告効果の不確実性や分布を理解するため。 |
特徴 | 各メディアのROIとそのばらつきを視覚化。信頼区間が狭いほど、効果の予測が安定していると解釈。 |
解釈例 | ネットのROIの95%信頼区間が狭く、安定した効果が期待できる。 |
⑤左上から3番目: 広告効果の減衰グラフ
詳細はこちら
説明 | 概要 |
---|---|
内容 | メディアごとの広告効果の減衰率(Adstock効果)を示したグラフ。 |
目的 | 広告効果の持続性をメディアごとに比較するため。 |
特徴 | 幾何学的減衰(geometric )の場合は固定値。ワイブル型(weibull )の場合は時間変化を伴う。 |
解釈例 | テレビ広告は減衰率が低く、効果が長期的に続く。 |
⑥右上から3番目: 効果の即時性とキャリーオーバー効果の割合
詳細はこちら
説明 | 概要 |
---|---|
内容 | メディアごとの即時効果(その期間内の影響)とキャリーオーバー効果(過去の影響)の割合を示す積み上げ棒グラフ。 |
目的 | メディアの影響が短期的か長期的かを分析するため。 |
解釈例 | ネット広告は即時効果が80%。テレビ広告はキャリーオーバー効果が60%で、長期的影響が大きい。 |
⑦左下: 飽和曲線のプロット
詳細はこちら
説明 | 概要 |
---|---|
内容 | 各メディアの飽和効果(Saturation)を記述した曲線プロット。 |
目的 | 広告費用の追加投入が成果にどれだけ寄与するかを視覚化するため。 |
特徴 | 曲線が平坦な場合、効果が飽和している(オーバースペンドの可能性)。mROAS(限界費用対効果)も参考にできる。 |
解釈例 | TV広告は曲線が急峻で、追加投資に対する効果が大きい。 |
⑧右下: 残差プロット
詳細はこちら
説明 | 概要 |
---|---|
内容 | 実績値と予測値の残差(誤差)をプロット。 |
目的 | モデルのフィットの良さを確認し、説明できていない要因を検討するため。 |
特徴 | 点がX軸の周りに均等に散らばっていれば良好なフィット。パターンが見える場合、モデルに不足している変数がある可能性。 |
解釈例 | 2018年中盤に外れ値が見える→特定の要因(未考慮のキャンペーンなど)が影響した可能性。 |
Step 4|モデルの選択
先ほど作成したモデルの中から、ビジネスの実情にあったモデルを1つ選択します(今回は"3-131-13"
を選択しました)。後の最適化で使用するためにjson
形式でモデルをrobyn_write()
関数を使ってエクスポートしておきます。
#### Step 4: モデルの選択と保存
# 選択するモデルのIDを指定(上で実行したモデルから選択)
select_model <- "3_131_13" # ご自身で最適なものを選んでください
# JSON形式でモデルをエクスポート
ExportedModel <- robyn_write(
InputCollect = InputCollect,
OutputCollect = OutputCollect,
select_model = select_model,
export = create_files
)
print(ExportedModel)
# 選択したモデルのOnePagerを作成
myOnePager <- robyn_onepagers(
InputCollect = InputCollect,
OutputCollect = OutputCollect,
select_model = select_model,
export = FALSE
)
# OnePagerを確認してみる
myOnePager[[select_model]]$patches$plots[[1]] #横向きウォーターフォール
myOnePager[[select_model]]$patches$plots[[2]] #予測と実績の推移
myOnePager[[select_model]]$patches$plots[[3]] #貢献比と予算比
myOnePager[[select_model]]$patches$plots[[4]] #CPA with 95% CI&mean
…
Step 5|選択したモデルで予算最適化を実施
続いてStep4で保存したモデルで予算の最適化を実施します。robyn_allocator()
関数を使って最適化を行います。
具体的におこなっていることとしては、現状の広告予算を0.7倍~1.2倍にする中での最適解を求めています。
#### Step 5: 選択したモデルで予算最適化を実施
# 選択したモデルのサマリを表示
print(ExportedModel)
# 制約条件の順序は次の順番で指定する必要があります
InputCollect$paid_media_spends
## シナリオ "max_response": 与えられた予算での売上最大化を目指した予算最適化を実施
# 例: date_rangeを指定しない場合、直近1カ月の予算最適化を行う
AllocatorCollect_1 <- robyn_allocator(
InputCollect = InputCollect,
OutputCollect = OutputCollect,
select_model = select_model,
# date_range = NULL, # 指定しない場合は直近1カ月が対象期間となる
# total_budget = NULL, # 指定しない場合はdate_range内の総支出額がデフォルト
channel_constr_low = c(0.7, 0.7), # メディア数と同じ長さで指定
channel_constr_up = c(1.2, 1.2), # メディア数と同じ長さで指定
# channel_constr_multiplier = 3, # メディア予算制約の拡張係数(必要なら指定)
scenario = "max_response", # シナリオ: 最大レスポンスを目指す
export = create_files # 結果をファイルにエクスポートするかどうか
)
# 最適化の結果を表示&プロット
print(AllocatorCollect_1)
plot(AllocatorCollect_1)
上記画像は次のように見ます。
① Total Budget Omtimization Result(上段のバーグラフ)
-
概要: 広告費の最適化結果を棒グラフで表現しています。3つの異なるシナリオ(
Initial
,Bounded
,Bounded×3
)での総広告費用(total spend
)と総レスポンス(total response
)の変化を表します -
ポイント:
- Initial: 現在の予算配分に基づく広告効果
- Bounded: 制約条件(例: 各広告の最低/最高支出割合)を考慮した最適化結果
- Bounded×3: 制約条件をさらに広げたシナリオ(上限を3倍に拡大)の最適化結果
-
解釈例:
- Boundedシナリオでは、広告支出を変えずに効果が4.28%増加。
- Bounded×3シナリオでは、広告費を増加させ、効果が12.2%増加。
② Budget Allocation per Paid Media Variable per Day(中段の表)
- 概要: メディアごとの支出シェアと効果シェアを示した表です。
-
列の説明:
-
abs.mean spend
: 平均的な広告費用(日単位)。 -
mean spend%
: 広告費全体の中での割合。 -
mean response%
: レスポンス全体の中での寄与割合。 -
mean ROAS
: 平均ROAS(レスポンス / 支出)。 -
mROAS
: 限界ROAS(追加的な1単位の支出による効果)。
-
-
解釈例:
-
Net_Ad_Spend
は支出割合が 33% に対して効果寄与が 9.1%。一方でTV_Ad_Spend
は支出割合が 67% に対して効果寄与が 90.9%。 -
TV_Ad_Spend
のROASが高いことから、より効率的なチャネルであると判断できる。
-
③ Simulated Response Curve per Day(下段のグラフ)
- 概要: メディアごとのレスポンス曲線(飽和曲線)を示しています。それぞれのメディアの支出量に対して、どれだけの効果(レスポンス)が得られるかを視覚化したものです。
- *ポイント:
- 横軸: メディアへの広告支出。
- 縦軸: 総レスポンス(例: 売上やコンバージョン)。
- Carryover(灰色部分): 広告支出のキャリーオーバー効果(過去の広告支出の影響)。
- Initial(黒い点): 現在の広告支出位置。
- Bounded(青い点): 最適化された支出位置。
- Bounded x3(茶色の点): 制約を広げた最適化結果。
-
解釈例:
-
Net_Ad_Spend
では、現在の支出(Initial
)が飽和点に近いため、効果の増加は限定的。 - 一方、
TV_Ad_Spend
ではまだ効果が増加する余地があり、投資を増やす価値がある。
-
Step 6|モデルをリフレッシュしてより良いモデルを目指す
常に新しいデータが増えていく実務の現場では、モデルをどんどんアップデートしていく必要があります。そこでrobyn_refresh()
関数というものを使うことで、初期のモデルを基にモデルのリフレッシュを行うことができます。ただし、これに関しては日本語版公式ドキュメントにも記載してありますが、モデルのリフレッシュ機能は十分にテストされていないため、不安定なリフレッシュ結果を返してしまう可能性があるようです。この機能が十分にテストされたら、またこの機能の使い方に関しても記事を追加していこうと思います。
まとめ
今回はmeta社のRobynを用いたMMMの実践をやってみましたが、やはりRobynの可能性は凄まじいものです…!
引き続き、Robynに関する記事もアウトプットして参ります。
Discussion