Configurer le modèle

Vous pouvez personnaliser et configurer la spécification du modèle de base Meridian selon vos besoins spécifiques, par exemple en personnalisant les a priori du ROI, en ajustant la saisonnalité, en définissant la durée maximale de report, en utilisant la couverture et la fréquence, et plus encore. Pour en savoir plus sur le modèle de base et les options de Meridian, consultez la section Le modèle Meridian.

Spécification de modèle par défaut

Vous pouvez utiliser la spécification de modèle par défaut suivante pour commencer à créer votre modèle :

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,
)

Définir les a priori

Vous pouvez personnaliser les a priori dans la spécification de modèle par défaut. Chaque paramètre dispose de son propre a priori indépendant, qui peut être défini par l'argument prior dans la ModelSpec de Meridian. Pour en savoir plus sur les a priori et les exceptions, consultez Distributions a priori par défaut.

L'exemple suivant personnalise les distributions a priori du ROI pour chaque canal média. Dans cet exemple, les a priori du ROI pour les canaux média sont différents.

  • Canal 1 : LogNormal(0.2, 0.7)
  • Canal 2 : LogNormal(0.3, 0.9)
  • Canal 3 : LogNormal(0.4, 0.6)
  • Canal 4 : LogNormal(0.3, 0.7)
  • Canal 5 : LogNormal(0.3, 0.6)
  • Canal 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)

Où le prior dans ModelSpec est un objet PriorDistribution spécifiant la distribution a priori de chaque ensemble de paramètres de modèle. Chaque paramètre dispose de son propre a priori indépendant, qui peut être défini par le constructeur prior_distribution.PriorDistribution().

Les paramètres de modèle avec un indice m (par exemple, roi_m) peuvent avoir une dimensionnalité égale au nombre de canaux média ou être unidimensionnels. Lorsque la dimensionnalité est égale au nombre de canaux média, l'ordre des valeurs de paramètre dans l'a priori personnalisé correspond à l'ordre dans data.media_channel (un a priori personnalisé est donc défini pour chaque canal média respectif). Si vous ne parvenez pas à déterminer un a priori personnalisé pour certains canaux média, vous pouvez utiliser manuellement la valeur tfd.LogNormal(0.2, 0.9) par défaut. Lorsqu'un a priori unidimensionnel est transmis, la dimension unique est utilisée pour tous les canaux média.

La logique de définition des a priori pour les paramètres de modèle avec un indice c (par exemple, gamma_c) est identique à celle de l'indice m. Pour les indices c, la dimensionnalité peut être égale au nombre de variables de contrôle ou unidimensionnelle. Lorsque la dimensionnalité est égale au nombre de variables de contrôle, l'ordre des valeurs de paramètre dans l'a priori personnalisé correspond à l'ordre dans data.control_variable (un a priori personnalisé est donc défini pour chaque variable de contrôle respective).

L'exemple suivant montre qu'un seul chiffre est utilisé pour définir le même a priori du ROI pour chaque canal. Dans cet exemple, les a priori du ROI pour les deux canaux média sont identiques, et sont tous deux représentés par LogNormal(0.2, 0.9).

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)

Important : Notez que Meridian dispose d'un paramètre ROI (roi_rf) et d'un paramètre bêta (beta_rf) distincts pour les canaux qui comportent des données de couverture et de fréquence. Par conséquent, il est nécessaire d'apporter certaines modifications aux extraits de code mentionnés précédemment lorsque des canaux spécifiques disposent de telles données. Dans cet exemple, les canaux 4 et 5 comportent des données de couverture et de fréquence.

  • Afin de personnaliser les distributions a priori du ROI pour chaque canal média :

    # 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)
    

Notez que l'ordre des valeurs de paramètre dans roi_rf_mu et roi_rf_sigma doit correspondre à data.rf_channel.

  • Afin de définir les mêmes a priori du ROI pour tous les canaux média :

    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)
    

Utiliser une répartition entre données d'entraînement et de test (facultatif)

Nous vous recommandons d'utiliser une répartition entre données d'entraînement et de test pour éviter le surapprentissage et vous assurer que le modèle se généralise correctement avec les nouvelles données. Pour ce faire, utilisez holdout_id. Il s'agit d'une étape facultative.

L'exemple suivant montre un argument holdout_id qui définit de manière aléatoire 20 % des données en tant que groupe test :

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)

holdout_id est un tenseur booléen facultatif de dimensions (n_geos x n_times) ou (n_times), qui indique les observations exclues de l'échantillon d'entraînement. Seule la variable de réponse est exclue de l'échantillon d'entraînement, et les variables média sont toujours incluses, car elles peuvent affecter l'adstock des semaines suivantes. Par défaut : None (ce qui signifie qu'il n'y a pas de zones géographiques ni de périodes de validation).

Affiner l'ajustement de saisonnalité automatique (facultatif)

Meridian applique un ajustement de saisonnalité automatique à l'aide d'une approche à intercept aléatoire. Vous pouvez affiner les effets en ajustant la valeur de knots. Pour en savoir plus, consultez Fonctionnement de l'argument knots.

knots est un entier ou une liste d'entiers facultatifs indiquant les nœuds utilisés pour estimer les effets temporels. Lorsque knots est une liste d'entiers, les emplacements des nœuds sont fournis par cette liste, où 0 correspond à un nœud dans la première période, 1 à un nœud dans la deuxième période, etc., et (n_times - 1) correspond à un nœud dans la dernière période.

Lorsque knots est un entier, il existe un nombre correspondant de nœuds avec des emplacements à intervalles égaux sur les périodes, y compris des nœuds à 0 et (n_times - 1). Lorsque knots correspond à 1, un seul coefficient de régression commun est utilisé pour toutes les périodes.

Si knots est défini sur None, le nombre de nœuds utilisés est égal au nombre de périodes dans le cas d'un modèle géographique. Cela revient à ce que chaque période dispose de son propre coefficient de régression. Pour les modèles nationaux, si knots est défini sur None, le nombre de nœuds utilisé est 1. Par défaut, sa valeur est définie sur None.

Pour en savoir plus, consultez Choisir le nombre de nœuds pour les effets temporels dans le modèle.

Exemples

  • Définissez knots sur 1 pour qu'il n'y ait pas d'ajustement de saisonnalité automatique. Dans ce cas, nous vous recommandons d'inclure vos propres variables indicatrices de saisonnalité ou de jours fériés en tant que variables de contrôle :

    model_spec = spec.ModelSpec(knots=1)
    
  • Définissez knots sur un nombre relativement élevé :

    knots = round(0.8 * n_times)
    model_spec = spec.ModelSpec(knots=knots)
    
  • Définissez des nœuds tous les quatre points temporels :

    knots = np.arange(0, n_times, 4).tolist()
    model_spec = spec.ModelSpec(knots=knots)
    
  • Définissez des nœuds pour qu'il y ait un nœud en novembre et en décembre, mais pour qu'ils soient relativement rares ailleurs. Pour que cet exemple soit plus pratique, nous partons du principe qu'il n'y a que 12 points de données et que les données sont mensuelles (cette hypothèse n'est ni réaliste, ni recommandée). Cet exemple est résumé dans le tableau suivant :

    Définir des nœuds par mois

  • Pour définir des nœuds au niveau des indices 0, 3, 6, 10 et 11 :

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

Vous pouvez utiliser une approche similaire pour assurer la présence de nœuds pendant les principaux jours fériés.

Ajuster la calibration du ROI (facultatif)

Meridian introduit une méthode de calibration du ROI qui reconfigure le ROI en tant que paramètre de modèle. Pour en savoir plus, consultez A priori du ROI pour la calibration.

Par défaut, le même a priori non informatif sur le ROI est appliqué à tous les canaux média. Vous pouvez ajuster cette fonctionnalité en procédant comme suit :

  • Désactiver la calibration du ROI
  • Définir la période de calibration du ROI

Désactiver la calibration du ROI

Vous pouvez désactiver la fonctionnalité de calibration du ROI à l'aide de media_prior_type='coefficient' et rf_prior_type='coefficient' :

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

L'argument media_prior_type indique si vous devez utiliser un a priori sur roi_m, mroi_m ou beta_m dans PriorDistribution. Par défaut : 'roi' (recommandé)

Définir la période de calibration du ROI

Bien que les coefficients de régression de l'effet du média n'aient pas d'effets qui varient dans le temps, il existe un argument de fenêtre de calibration pour définir l'a priori du ROI (ou du ROIm). En effet, à un moment donné, le ROI (ou le ROIm) dépend de facteurs supplémentaires qui peuvent varier dans le temps :

  • Les courbes de Hill modélisent les rendements décroissants non linéaires de l'exécution média. Par conséquent, le volume d'exécution média à un moment donné peut avoir un impact sur le ROI.
  • Affectation des médias à différentes zones géographiques avec des niveaux d'efficacité différents.
  • Coût de l'exécution média.

Vous pouvez calibrer la MMM à l'aide d'un sous-ensemble de données lorsque les résultats des tests ne reflètent pas le retour sur les dépenses publicitaires (ROAS) de modélisation que la MMM vise à mesurer. Par exemple, la période de test n'est pas alignée sur la période des données de la MMM. Pour en savoir plus, consultez Calibration du modèle mix média avec des a priori bayésiens et A priori et calibration du ROI.

L'exemple suivant montre comment spécifier la période de calibration du ROI du '2021-11-01' au '2021-12-20' pour le canal 1. Tous les canaux média non spécifiés dans la roi_period utiliseront toutes les périodes disponibles pour la calibration du ROI.

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)

roi_calibration_period est un tableau booléen facultatif de forme (n_media_times, n_media_channels) indiquant le sous-ensemble time pour la calibration du ROI média. Si la valeur est None, toutes les périodes sont utilisées pour la calibration du ROI média. Par défaut : None.

Notez que Meridian utilise un paramètre différent (rf_roi_calibration_period) pour les canaux qui comportent des données de couverture et de fréquence. L'exemple suivant montre comment spécifier la période de calibration du ROI du '2021-11-01' au '2021-12-20' pour le canal 5, qui utilise la couverture et la fréquence comme entrées.

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)

rf_roi_calibration_period est un tableau booléen facultatif de forme (n_media_times, n_rf_channels). Si la valeur est None, toutes les périodes et zones géographiques sont utilisées pour la calibration du ROI média. Par défaut : None.

Définir des attributs supplémentaires (facultatif)

Si nécessaire, vous pouvez modifier les attributs restants dans la spécification de modèle par défaut. Cette section décrit les attributs restants et fournit des exemples illustrant comment modifier les valeurs.

baseline_geo

Entier facultatif ou chaîne pour la zone géographique de référence. Celle-ci est traitée comme la zone géographique de référence dans l'encodage factice des zones géographiques. Les zones géographiques qui ne sont pas de référence ont une variable d'indicateur tau_g correspondante. Cela signifie qu'elles présentent une variance a priori plus élevée que la zone géographique de référence. Lorsque la valeur est définie sur None, la zone géographique la plus peuplée est utilisée comme référence. Par défaut : None

L'exemple suivant montre la zone géographique de référence définie sur 'Geo10' :

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

hill_before_adstock

Cette valeur booléenne indique si la fonction Hill doit être appliquée avant la fonction Adstock, contrairement à l'ordre par défaut (Adstock avant Hill). Par défaut : False

Les exemples suivants montrent que la fonction Hill sera appliquée en premier, la valeur étant définie sur True :

model_spec = spec.ModelSpec(hill_before_adstock=True)

max_lag

Cet entier indique le nombre maximal de périodes de décalage (>= 0) à inclure dans le calcul de l'adstock. La valeur peut aussi être définie sur None, ce qui équivaut à l'intégralité de la période de modélisation. Par défaut : 8

L'exemple suivant remplace la valeur par 4 :

model_spec = spec.ModelSpec(max_lag=4)

media_effects_dist

Cette chaîne permet de spécifier la répartition des effets aléatoires des médias dans différentes zones géographiques. Les valeurs autorisées sont 'normal' ou 'log_normal'. Par défaut : 'log_normal'

Où :

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

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

L'exemple suivant montre comment remplacer la valeur par 'normal' :

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

control_population_scaling_id

Ce tenseur booléen facultatif de dimension (n_controls) indique les variables de contrôle pour lesquelles la valeur de contrôle sera ajustée selon la population. Par défaut : None

L'exemple suivant spécifie que la variable de contrôle à l'index 1 doit être ajustée selon la population :

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

Cette valeur booléenne indique si une variance résiduelle unique doit être utilisée pour chaque zone géographique. Si la valeur est False, une seule variance résiduelle est utilisée pour toutes les zones géographiques. Par défaut : False

L'exemple suivant définit le modèle pour qu'il utilise une variance résiduelle unique pour chaque zone géographique :

model_spec = spec.ModelSpec(unique_sigma_for_each_geo=True)