Modell konfigurieren

Sie können die Spezifikation des Meridian-Basismodells an Ihre spezifischen Bedürfnisse anpassen und entsprechend konfigurieren, z. B. indem Sie die ROI-Priors anpassen, saisonale Schwankungen berücksichtigen, die maximale Dauer für den Carryover-Effekt festlegen oder Daten zu Reichweite und Häufigkeit nutzen. Weitere Informationen zum Meridian-Basismodell und zu den Optionen finden Sie im Abschnitt Das Meridian-Modell.

Standardmodellspezifikation

Sie können die folgende Standardmodellspezifikation verwenden, um mit dem Erstellen Ihres Modells zu beginnen:

model_spec = spec.ModelSpec(
    prior=prior_distribution.PriorDistribution(),
    media_effects_dist='log_normal',
    hill_before_adstock=False,
    max_lag=8,
    unique_sigma_for_each_geo=False,
    media_prior_type='roi',
    roi_calibration_period=None,
    rf_prior_type='roi',
    rf_roi_calibration_period=None,
    organic_media_prior_type='contribution',
    organic_rf_prior_type='contribution',
    non_media_treatments_prior_type='contribution',
    knots=None,
    baseline_geo=None,
    holdout_id=None,
    control_population_scaling_id=None,
)

Priors festlegen

Sie können die Priors in der Standardmodellspezifikation anpassen. Jeder Parameter erhält einen eigenen, unabhängigen Prior, der mit dem prior-Argument in der ModelSpec von Meridian festgelegt wird. Informationen zu den Priors und Ausnahmen finden Sie unter Standard-Prior-Verteilungen.

Im folgenden Beispiel werden die ROI-Prior-Verteilungen für jeden Media-Channel angepasst. In diesem Fall unterscheiden sich die ROI-Priors für die einzelnen Media-Channels.

  • Channel 1: LogNormal(0.2, 0.7)
  • Channel 2: LogNormal(0.3, 0.9)
  • Channel 3: LogNormal(0.4, 0.6)
  • Channel 4: LogNormal(0.3, 0.7)
  • Channel 5: LogNormal(0.3, 0.6)
  • Channel 6: LogNormal(0.4, 0.5)
my_input_data = input_data.InputData( ... )
build_media_channel_args = my_input_data.get_paid_media_channels_argument_builder()

# Assuming Channel1,...,Channel6 are all media channels.
roi_m = build_media_channel_args(
  Channel1=(0.2, 0.7),
  Channel2=(0.3, 0.9),
  Channel3=(0.4, 0.6),
  Channel4=(0.3, 0.7),
  Channel5=(0.3, 0.6),
  Channel6=(0.4, 0.5),
) # This creates a list of channel-ordered (mu, sigma) tuples.
roi_m_mu, roi_m_sigma = zip(*roi_m)

prior = prior_distribution.PriorDistribution(
    roi_m=tfp.distributions.LogNormal(
        roi_m_mu, roi_m_sigma, name=constants.ROI_M
    )
)
model_spec = spec.ModelSpec(prior=prior)

Dabei ist prior in ModelSpec ein PriorDistribution-Objekt, das die Prior-Verteilung für jede Gruppe von Modellparametern angibt. Für jeden Parameter wird ein eigener unabhängiger Prior mit dem prior_distribution.PriorDistribution()-Konstruktor festgelegt.

Modellparameter mit einem m nach dem Unterstrich (z. B. roi_m) können entweder mehrdimensional (für jeden Media-Channel gibt es einen eigenen Wert) oder eindimensional sein. Wenn die Dimensionalität der Anzahl der Media-Channels entspricht, stimmt die Reihenfolge der Parameterwerte in der benutzerdefinierten Prior-Verteilung mit der in data.media_channel überein. Das bedeutet, dass für jeden Media-Channel eine benutzerdefinierte Prior-Verteilung festgelegt wird. Wenn Sie für einige der Media-Channels keine benutzerdefinierte Prior-Verteilung festlegen können, können Sie stattdessen die Standardverteilung tfd.LogNormal(0.2, 0.9) verwenden. Wird ein eindimensionaler Prior übergeben, wird die einzelne Dimension für alle Media-Channels verwendet.

Die Logik zum Festlegen von Priors für Modellparameter mit einem c nach dem Unterstrich (z. B. gamma_c) ist dieselbe wie für das m. Beim c nach dem Unterstrich kann die Dimensionalität entweder der Anzahl der Kontrollvariablen entsprechen oder eindimensional sein. Wenn die Dimensionalität der Anzahl der Kontrollvariablen entspricht, stimmt die Reihenfolge der Parameterwerte in der benutzerdefinierten Prior-Verteilung mit der in data.control_variable überein. Das bedeutet, dass für jede Kontrollvariable eine benutzerdefinierte Prior-Verteilung festgelegt wird.

Im folgenden Beispiel wird nur eine Zahl verwendet, um für jeden Channel denselben ROI-Prior festzulegen. In diesem Fall sind die ROI-Priors für die zwei Media-Channels identisch, wobei beide als LogNormal(0.2, 0.9) dargestellt sind.

roi_mu = 0.2
roi_sigma = 0.9
prior = prior_distribution.PriorDistribution(
    roi_m=tfp.distributions.LogNormal(roi_mu, roi_sigma, name=constants.ROI_M)
)
model_spec = spec.ModelSpec(prior=prior)

Wichtig: Meridian verwendet einen separaten ROI-Parameter (roi_rf) und einen separaten Beta-Parameter (beta_rf) für die Channels mit Daten zu Reichweite und Häufigkeit. Für entsprechende Channels sind daher einige Änderungen an den zuvor genannten Code-Snippets erforderlich. In diesem Beispiel enthalten Channel 4 und Channel 5 Daten zu Reichweite und Häufigkeit.

  • So passen Sie die ROI-Prior-Verteilungen für die einzelnen Media-Channels an:

    # ROI prior for channels without R&F data
    build_media_channel_args = my_input_data.get_paid_media_channels_argument_builder()
    roi_m = build_media_channel_args(
      Channel1=(0.2, 0.7),
      Channel2=(0.3, 0.9),
      Channel3=(0.4, 0.6),
      Channel4=(0.3, 0.7),
    )
    roi_m_mu, roi_m_sigma = zip(*roi_m)
    
    # ROI prior for channels with R&F data
    build_rf_channel_args = my_input_data.get_paid_rf_channels_argument_builder()
    roi_rf = build_rf_channel_args(
      Channel5=(0.3, 0.6),
      Channel6=(0.4, 0.5),
    ]
    roi_rf_mu, roi_rf_sigma = zip(*roi_rf)
    
    prior = prior_distribution.PriorDistribution(
        roi_m=tfp.distributions.LogNormal(
            roi_m_mu, roi_m_sigma, name=constants.ROI_M
        ),
        roi_rf=tfp.distributions.LogNormal(
            roi_rf_mu, roi_rf_sigma, name=constants.ROI_RF
        ),
    )
    model_spec = spec.ModelSpec(prior=prior)
    

Die Reihenfolge der Parameterwerte in roi_rf_mu und roi_rf_sigma muss mit data.rf_channel übereinstimmen.

  • So legen Sie dieselben ROI-Priors für alle Media-Channels fest:

    roi_mu = 0.2
    roi_sigma = 0.9
    prior = prior_distribution.PriorDistribution(
        roi_m=tfp.distributions.LogNormal(
            roi_mu, roi_sigma, name=constants.ROI_M),
        roi_rf=tfp.distributions.LogNormal(
            roi_mu, roi_sigma, name=constants.ROI_RF
        ),
    )
    model_spec = spec.ModelSpec(prior=prior)
    

Trainings- und Testdaten aufteilen (optional)

Wir empfehlen, Trainings- und Testdaten zu trennen, um Überanpassung zu vermeiden und sicherzustellen, dass das Modell gut mit neuen Daten generalisiert. Dazu kann holdout_id verwendet werden. Dieser Schritt ist optional.

Im folgenden Beispiel wird ein holdout_id-Argument verwendet, mit dem 20 % der Daten zufällig als Testgruppe festgelegt werden:

np.random.seed(1)
test_pct = 0.2  # 20% of data are held out
n_geos = len(data.geo)
n_times = len(data.time)
holdout_id = np.full([n_geos, n_times], False)
for i in range(n_geos):
  holdout_id[
    i,
    np.random.choice(
      n_times,
      int(np.round(test_pct * n_times)),
    )
  ] = True
model_spec = spec.ModelSpec(holdout_id=holdout_id)

Dabei ist holdout_id ein optionaler boolescher Tensor mit den Dimensionen (n_geos × n_times) oder (n_times), der angibt, welche Beobachtungen aus der Trainingsstichprobe ausgeschlossen werden. Nur die Antwortvariable wird aus der Trainingsstichprobe ausgeschlossen. Die Media-Variablen sind weiterhin enthalten, da sie sich auf den Adstock der Folgewochen auswirken können. Standard: None (d. h. es gibt keine geografischen und zeitlichen Ausschlüsse)

Automatische saisonale Anpassung abstimmen (optional)

Meridian wendet eine automatische saisonale Anpassung durch einen zeitvariablen Schnittpunktansatz an. Die Auswirkungen können durch Anpassung des Werts von knots optimiert werden. Weitere Informationen finden Sie unter Funktionsweise des Arguments knots.

knots ist eine optionale Ganzzahl oder Liste mit Ganzzahlen, die die Knoten angibt, die zur Schätzung der Zeiteffekte verwendet werden. Wenn knots eine Liste von Ganzzahlen ist, werden die Knotenpositionen durch diese Liste angegeben. Dabei entspricht „0“ einem Knoten im ersten Zeitraum, „1“ einem Knoten im zweiten Zeitraum usw., wobei (n_times - 1) einem Knoten im letzten Zeitraum entspricht.

Ist knots eine Ganzzahl, gibt es eine entsprechende Anzahl von Knoten, deren Positionen gleichmäßig über die Zeiträume hinweg verteilt sind, einschließlich Knoten bei null und (n_times - 1). Wenn knots gleich 1 ist, wird für alle Zeiträume ein gemeinsamer Regressionskoeffizient verwendet.

Wenn knots auf None festgelegt ist, entspricht die Anzahl der verwendeten Knoten bei einem geografischen Modell der Anzahl der Zeiträume. Das bedeutet, dass jeder Zeitraum einen eigenen Regressionskoeffizienten hat. Wenn knots für nationale Modelle auf None gesetzt ist, ist die Anzahl der Knoten 1. Standardmäßig ist der Wert auf None gesetzt.

Weitere Informationen finden Sie unter Anzahl der Knoten für Zeiteffekte im Modell auswählen.

Beispiele

  • Wenn Sie knots auf 1 setzen, findet keine automatische saisonale Anpassung statt. In diesem Fall empfehlen wir, eigene Dummy-Variablen für saisonale Schwankungen oder Feiertage als Kontrollvariablen hinzuzufügen:

    model_spec = spec.ModelSpec(knots=1)
    
  • Wenn Sie knots auf eine relativ große Zahl festlegen:

    knots = round(0.8 * n_times)
    model_spec = spec.ModelSpec(knots=knots)
    
  • Knoten jeweils nach 4 Zeitpunkten setzen:

    knots = np.arange(0, n_times, 4).tolist()
    model_spec = spec.ModelSpec(knots=knots)
    
  • Knoten so setzen, dass es im November und Dezember spezifische Knoten gibt, außerhalb dieser Monate aber relativ wenige Knoten gesetzt werden. Um dieses Beispiel nachvollziehbarer zu machen, nehmen wir an, dass es nur 12 Datenpunkte gibt und dass die Daten monatlich sind (diese Annahme ist nicht realistisch oder empfehlenswert). Dieses Beispiel ist in der folgenden Tabelle zusammengefasst:

    Knoten nach Monat festlegen

  • So setzen Sie Knoten an den Indexen 0, 3, 6, 10 und 11:

    knots = [0, 3, 6, 10, 11]
    model_spec = spec.ModelSpec(knots=knots)
    

Sie können einen ähnlichen Ansatz nutzen, um Knoten für wichtige Feiertage zu setzen.

ROI-Abstimmung optimieren (optional)

Meridian führt eine Methode zur ROI-Abstimmung ein, mit der der ROI als Modellparameter neu parametrisiert wird. Weitere Informationen finden Sie unter ROI-Priors für die Abstimmung.

Standardmäßig wird für alle Media-Channels derselbe nicht informative Prior für den ROI verwendet. Sie haben folgende Möglichkeiten, diese Funktion anzupassen:

  • ROI-Abstimmung deaktivieren
  • Zeitraum für die ROI-Abstimmung festlegen

ROI-Abstimmung deaktivieren

Sie können die Funktion zur ROI-Abstimmung mit media_prior_type='coefficient' und rf_prior_type='coefficient' deaktivieren:

model_spec = spec.ModelSpec(
    media_prior_type='coefficient',
    rf_prior_type='coefficient',
)

Das Argument media_prior_type gibt an, ob ein Prior für roi_m, mroi_m oder beta_m in der PriorDistribution verwendet werden soll. Standard: 'roi' (empfohlen)

Zeitraum für ROI-Abstimmung festlegen

Obwohl die Regressionskoeffizienten des Media-Effekts keine zeitabhängigen Auswirkungen haben, spricht einiges dafür, ein Abstimmungsfenster für die Festlegung des ROI-Prior (oder Grenz-ROI-Prior) festzulegen. Das liegt daran, dass der ROI (oder Grenz-ROI) zu einem bestimmten Zeitpunkt von zusätzlichen Faktoren abhängt, die sich im Laufe der Zeit ändern können:

  • Die Hill-Kurven modellieren die nicht linearen, sinkenden Renditen der Media-Ausführung. Daher kann die Anzahl der Media-Ausführungen zu einem bestimmten Zeitpunkt den ROI beeinflussen.
  • Media-Verteilung über geografische Einheiten mit unterschiedlicher Effektivität.
  • Kosten für die Media-Ausführung.

Sie können das MMM mit einer Teilmenge der Daten abstimmen, wenn die Testergebnisse nicht den modellierten ROAS (Return on Advertising Spend) widerspiegeln, den das MMM messen soll. Zum Beispiel wird der Zeitraum des Tests nicht mit dem Zeitraum der MMM-Daten abgestimmt. Weitere Informationen finden Sie unter Media-Mix-Modell mit bayesschen Priors abstimmen und ROI-Priors und ‑Abstimmung.

Im folgenden Beispiel sehen Sie, wie Sie den Zeitraum für die ROI-Abstimmung für Channel 1 vom '2021-11-01' bis zum '2021-12-20' festlegen. Für alle Media-Channels, die nicht in roi_period angegeben sind, werden alle verfügbaren Zeiträume für die ROI-Abstimmung verwendet.

roi_period = {
  'Channel1': [
    '2021-11-01',
    '2021-11-08',
    '2021-11-15',
    '2021-11-22',
    '2021-11-29',
    '2021-12-06',
    '2021-12-13',
    '2021-12-20',
  ],
}

roi_calibration_period = np.zeros((len(data.time), len(data.media_channel)))
for i in roi_period.items():
  roi_calibration_period[
      np.isin(data.time.values, i[1]), data.media_channel.values == i[0]
  ] = 1

roi_calibration_period[
    :, ~np.isin(data.media_channel.values, list(roi_period.keys()))
] = 1

model_spec = spec.ModelSpec(roi_calibration_period=roi_calibration_period)

Dabei ist roi_calibration_period ein optionales boolesches Array der Form (n_media_times, n_media_channels), das die Teilmenge time für die ROI-Abstimmung von Media angibt. Wenn None festgelegt ist, werden alle Zeiträume für die ROI-Abstimmung für Media verwendet. Standard: None.

In Meridian wird für Channels mit Daten zu Reichweite und Häufigkeit ein anderer Parameter verwendet: rf_roi_calibration_period. Im folgenden Beispiel sehen Sie, wie Sie den Zeitraum für die ROI-Abstimmung für Channel 5 vom '2021-11-01' bis zum '2021-12-20' festlegen, wobei Reichweite und Häufigkeit als Eingaben verwendet werden.

roi_period = {
  'Channel5': [
    '2021-11-01',
    '2021-11-08',
    '2021-11-15',
    '2021-11-22',
    '2021-11-29',
    '2021-12-06',
    '2021-12-13',
    '2021-12-20',
  ],
}

rf_roi_calibration_period = np.zeros(len(data.time), len(data.rf_channel))
for i in roi_period.items():
  rf_roi_calibration_period[
      np.isin(data.time.values, i[1]), data.rf_channel.values == i[0]
  ] = 1

rf_roi_calibration_period[
    :, ~np.isin(data.rf_channel.values, list(roi_period.keys()))
] = 1

model_spec = spec.ModelSpec(rf_roi_calibration_period=rf_roi_calibration_period)

Dabei ist rf_roi_calibration_period ein optionales boolesches Array der Form (n_media_times, n_rf_channels). Wenn None festgelegt ist, werden alle Zeiträume und geografischen Einheiten für die ROI-Abstimmung für Media verwendet. Standard: None.

Zusätzliche Attribute festlegen (optional)

Sie können alle verbleibenden Attribute in der Standardmodellspezifikation nach Bedarf ändern. In diesem Abschnitt werden die verbleibenden Attribute beschrieben und Beispiele dafür gegeben, wie die Werte geändert werden können.

baseline_geo

Optionale Ganzzahl oder String für die geografische Baseline. Die geografische Baseline wird bei der Dummy-Codierung von geografischen Einheiten als Referenz behandelt. Andere geografische Einheiten (nicht Baseline) haben eine entsprechende tau_g-Indikatorvariable. Sie haben also eine höhere Prior-Varianz als die geografische Baseline. Ist None festgelegt, wird die geografische Einheit mit der größten Bevölkerung als Baseline verwendet. Standard: None.

Im folgenden Beispiel ist die geografische Baseline auf 'Geo10' gesetzt:

model_spec = spec.ModelSpec(baseline_geo='Geo10')

hill_before_adstock

Ein boolescher Wert, der angibt, ob die Hill-Funktion vor der Adstock-Funktion angewendet werden soll, im Gegensatz zur Standardreihenfolge von Adstock vor Hill. Standard: False.

In den folgenden Beispielen wird die Hill-Funktion zuerst angewendet. Dazu wird der Wert auf True gesetzt:

model_spec = spec.ModelSpec(hill_before_adstock=True)

max_lag

Eine Ganzzahl, die die maximale Anzahl der Verzögerungszeiträume angibt, die in die Adstock-Berechnung einbezogen werden sollen (>= 0). Sie kann auch auf None gesetzt werden, was dem gesamten Modellierungszeitraum entspricht. Standard: 8.

Im folgenden Beispiel wird der Wert in 4 geändert:

model_spec = spec.ModelSpec(max_lag=4)

media_effects_dist

Ein String, mit dem die Verteilung der zufälligen Media-Effekte über verschiedene geografische Einheiten angegeben wird. Zulässige Werte: 'normal' oder 'log_normal'. Standard: 'log_normal'.

Dabei gilt:

  • media_effects_dist='log_normal' ist \(\beta m,g\ {_\sim^{iid}} Lognormal(\beta m, \eta ^2m)\)

  • media_effects_dist='normal' ist \(\beta m,g\ {_\sim^{iid}} Normal (\beta m, \eta ^2m)\)

Im folgenden Beispiel sehen Sie, wie der Wert in 'normal' geändert wird:

model_spec = spec.ModelSpec(media_effects_dist='normal')

control_population_scaling_id

Optionaler boolescher Tensor der Dimension (n_controls), der die Kontrollvariablen angibt, für die der Kontrollwert nach Bevölkerung skaliert wird. Standard: None.

Im folgenden Beispiel wird die Kontrollvariable an der zweiten Position (Index 1) nach Bevölkerung skaliert:

control_population_scaling_id = np.full([n_controls], False)
control_population_scaling_id[1] = True
model_spec = spec.ModelSpec(
  control_population_scaling_id=control_population_scaling_id
)

unique_sigma_for_each_geo

Boolescher Wert, der angibt, ob für jede geografische Einheit eine eigene Residualvarianz verwendet werden soll. Wenn False festgelegt ist, wird für alle geografischen Einheiten eine gemeinsame Residualvarianz verwendet. Standard: False.

Im folgenden Beispiel wird das Modell so konfiguriert, dass für jede geografische Einheit eine eigene Residualvarianz verwendet wird:

model_spec = spec.ModelSpec(unique_sigma_for_each_geo=True)