Como o argumento knots funciona
O Meridian usa uma abordagem de intercepto com variação de tempo para modelar efeitos temporais (Spline (matemática) na Wikipédia; Ng, Wang e Dai. 2021). Essa abordagem modela os efeitos temporais \(\mu = [\mu_1, \dots, \mu_T]\) para cada um dos períodos \(T\)(uma MMM com 3 anos de dados semanais tem \(52 \times 3\) períodos). Os efeitos temporais \(T\) podem ser modelados com possivelmente menos de \(T\)parâmetros usando a relação:
\[\mu = W \ast b\]
Em que:
\(\mu\) é \(1 \times T\) , representando o efeito de cada tempo \(t=1, \dots ,T\), \(W\) é uma \(T \times K\) matriz determinante de ponderação
\(b\) (chamado de
knot_valuesno Meridian) é \(K \times 1\), em que \(K \leq T\).
A inferência bayesiana de distribuição a posteriori é feita em \(b\), que é traduzida em termos de\(\mu\) de acordo com a matriz de ponderação \(W\). O número de nós \(K\)é determinado pela entrada do usuário. A matriz de ponderação \(W\) é determinada pela distância L1 de um período até os dois nós vizinhos.
Para entender como a distância L1 determina a matriz de ponderação, considere o período\(9\), em que os dois nós vizinhos estão em \(6\) e \(11\). A distância L1 do período \(9\) e do nó \(11\) é \(2\). A distância L1 do período \(9\) e do nó \(6\) é \(3\). Portanto, o nó em \(6\) recebe a ponderação \(0.4 = 1 - \frac{3}{2+3} \) , e o nó em \(11\) recebe a ponderação\(0.6 = 1 - \frac{2}{2+3} \). A média ponderada desses dois nós vizinhos determina o valor de \(\mu_9\).
No caso de knots < n_times, há algum nível de redução de dimensionalidade. Os períodos de n_times são modelados com menos parâmetros n_times. A função de ponderação determina como os períodos são combinados.
Configurações padrão de nós no Meridian
Por padrão, o argumento knots em ModelSpec é definido como None,
e enable_aks é definido como False. Quando knots = None, o Meridian
define automaticamente o número de nós com base no tipo de modelo sendo executado:
geográfico ou nacional.
- Modelos geográficos usam
knots = n_timespor padrão: como esses modelos têm várias observações (uma por região) para cada período, a definição deknots = n_timesé matematicamente identificável. Isso dá ao modelo a máxima flexibilidade para se ajustar a variáveis de confusão temporais, o que minimiza o viés nas estimativas causais. Se você observar uma variância inaceitavelmente alta, reduza o número de nós manualmente ou use o AKS. - Modelos nacionais usam
knots = 1por padrão: os modelos nacionais têm apenas uma única observação por período. Um modelo comknots = n_timesestaria completamente saturado e não seria identificável. Definirknots = 1restringe os efeitos temporais a uma única interceptação constante, servindo como um valor de referência limpo e de baixa variância. É possível aumentar gradualmente o número de nós para capturar a sazonalidade conforme os graus de liberdade permitirem.
Automatic Knot Selection (AKS)
Escolher nós pode ser difícil, já que é necessário equilibrar a compensação de viés-variância para uma inferência causal confiável, incorporar o contexto de negócios para representar com precisão como o tempo influencia a mídia e os KPIs e aceitar tentativa e erro como parte do processo iterativo de ajuste do modelo.
Para lidar com esses desafios, o Meridian oferece o recurso de Automatic Knot Selection (AKS). Recomendamos começar com o AKS na maioria dos casos de uso, já que ele elimina a necessidade de adivinhação ao automatizar o processo de seleção de nós.
Usar o Automatic Knot Selection
Para ativar o AKS no seu modelo do Meridian, defina o parâmetro enable_aks como True
no ModelSpec.
from meridian.model import model
from meridian.model import spec
# `data` is an `InputData` object
model_spec = spec.ModelSpec(enable_aks=True)
mmm = model.Meridian(input_data=data, model_spec=model_spec)
Depois que ele estiver ativado no ModelSpec, você poderá recuperar a lista dos nós selecionados pelo Meridian.
knot_info = mmm.knot_info
selected_knots = knot_info.knot_locations
Depois de ativar o AKS no ModelSpec, é sempre uma boa ideia revisar
os nós selecionados para garantir que eles façam sentido no contexto dos seus dados.
Como o AKS funciona
Ele é inspirado na metodologia de Regressão spline com Automatic Knot Selection (em inglês), mas inclui várias melhorias específicas do Meridian. Basicamente, o algoritmo usa a base de spline linear para modelar a relação entre o tempo (nós) e a variável de resultado dimensionada. Ele usa uma abordagem de eliminação regressiva, começando com um conjunto completo de possíveis nós e removendo sequencialmente aqueles que não melhoram o ajuste do modelo. Esse ajuste é avaliado usando um método de regularização, que penaliza o modelo por complexidade desnecessária (ou seja, número de nós). Uma mudança importante na versão do Meridian é uma penalidade com reconhecimento geográfico, que incentiva o aumento no número de nós à medida que o número de regiões geográficas nos dados aumenta. Isso acontece porque, com mais regiões geográficas, há mais dados disponíveis para cada período. O conjunto ideal final de nós é determinado usando o critério de informação de Akaike (AIC, na sigla em inglês) para garantir que o modelo capture com precisão os padrões de tendência e sazonalidade.
Avançado: ajuste o parâmetro de penalidade do AKS
O algoritmo do AKS pode selecionar um grande número de nós. Isso pode ser
problemático para modelos nacionais ou com um pequeno número de regiões,
em que há poucos dados disponíveis para cada período. Se você observar um número incomum de nós
nesses casos, chame a função automatic_knot_selection()
para ajustar o algoritmo e reduzir o número de nós.
É possível mudar o argumento base_penalty em automatic_knot_selection para
definir o intervalo de pesquisa da penalidade de regularização. Por padrão, ele é definido como
np.geomspace(0.1, 100, 100), o que significa que o intervalo de pesquisa da penalidade de base padrão
é de 0.1 a 100. Você pode fornecer sua própria lista de parâmetros de penalidade.
Aumentar o parâmetro de penalidade aplica uma regularização mais forte,
o que reduz o número de nós selecionados. Por exemplo, é possível definir o intervalo de pesquisa
de 10 a 200 usando np.geomspace(10, 200, 100).
Também é possível definir o intervalo do número de nós considerados usando
os argumentos min_internal_knots e max_internal_knots.
import numpy as np
from meridian.model import knots
from meridian.model import model
from meridian.model import spec
# `data` is an `InputData` object; same as what will be passed to
# `model.Meridian`
aks = knots.AKS(data)
# Modify `base_penalty`, `min_internal_knots`, `max_internal_knots`
# arguments to encourage fewer knots
base_penalty = np.geomspace(10, 200, 100)
knot_locations = aks.automatic_knot_selection(base_penalty=base_penalty,
min_internal_knots=2,
max_internal_knots=10).knots
# You must use the 'knots' argument and NOT set 'enable_aks=True'.
model_spec = spec.ModelSpec(knots=knot_locations)
# `input_data` argument is the same `data` passed to `knots.AKS(data)`
mmm = model.Meridian(input_data=data, model_spec=model_spec)
Avançado: seleção de nós híbrida
É possível combinar o AKS com seu próprio conhecimento de domínio para usar uma abordagem híbrida. Isso permite aplicar uma lógica de negócios conhecida (como períodos de festas de fim de ano ou atualizações de modelo), enquanto o algoritmo do AKS identifica os nós restantes necessários.
Há duas maneiras principais de implementar uma abordagem híbrida:
- Ajuste manualmente os nós selecionados: execute o AKS, inspecione os nós selecionados e adicione ou remova nós manualmente antes de executar o modelo final.
- Especifique os nós necessários: transmita uma lista de nós obrigatórios ao algoritmo do AKS, que permite selecionar automaticamente os nós adicionais necessários.
Ajustar manualmente os nós selecionados
É possível adicionar ou remover nós manualmente de acordo com o contexto da sua empresa. Por exemplo, é possível adicionar nós durante a época de fim de ano para reduzir o viés nas estimativas ou remover alguns nós durante uma baixa temporada para diminuir a variância. Para mais detalhes sobre ajustes manuais de nós, consulte Compensação de viés-variância.
O snippet de código a seguir é um exemplo de como recuperar os nós
selecionados, adicionar um novo nó no momento 52 e usá-lo para definir um novo
ModelSpec.
import numpy as np
from meridian.model import model
from meridian.model import spec
# `data` is an `InputData` object
model_spec_with_aks = spec.ModelSpec(enable_aks=True)
mmm_with_aks = model.Meridian(input_data=data, model_spec=model_spec_with_aks)
# Retrieve selected knots from a model run with enable_aks=True
selected_knots = mmm_with_aks.knot_info.knot_locations
# Add a knot at time point 52
modified_knots = np.append(selected_knots, 52)
model_spec = spec.ModelSpec(knots=modified_knots)
mmm = model.Meridian(input_data=data, model_spec=model_spec)
Especificar os nós necessários para o AKS
É possível combinar o AKS com seu próprio conhecimento de domínio especificando
os locais de nós necessários diretamente no algoritmo. Para fazer isso, chame o
método automatic_knot_selection() e forneça um iterável de required_knots.
O algoritmo os inclui e seleciona automaticamente os nós adicionais necessários
para explicar da melhor forma os efeitos temporais, equilibrando o ajuste e a complexidade do modelo.
Essa abordagem é útil quando você quer forçar o posicionamento de nós em pontos de tempo específicos conhecidos e usar o AKS para o restante. Exemplo:
- "Sei que o mês de julho é um período único para minha empresa, por isso quero nós para cada semana de julho de cada ano. Deixe o AKS cuidar do resto."
- "Sei que a primeira semana de cada mês é um momento único para minha empresa, por isso quero nós em todas as primeiras semanas do mês. Deixe o AKS descobrir se preciso de mais nós em cada mês."
import numpy as np
from meridian.model import knots
from meridian.model import model
from meridian.model import spec
# `data` is an `InputData` object; same as what will be passed to
# `model.Meridian`
aks = knots.AKS(data)
# Require knots at specific time periods and automatically select the rest
required_knots = np.array([10, 20, 30])
knot_locations = aks.automatic_knot_selection(
required_knots=required_knots
).knots
# You must use the 'knots' argument and NOT set 'enable_aks=True'.
model_spec = spec.ModelSpec(knots=knot_locations)
# `input_data` argument is the same `data` passed to `knots.AKS(data)`
mmm = model.Meridian(input_data=data, model_spec=model_spec)
Atualização do modelo com seleção de nós híbridos
Ao atualizar um modelo com novos dados de série temporal (por exemplo, ao adicionar os dados do último trimestre a um conjunto de dados de vários anos), talvez seja interessante preservar os locais dos nós usados no modelo original para manter a consistência na tendência de base desse período inicial. Talvez você prefira que o AKS selecione novos nós para os dados recém-adicionados.
Para isso, transmita os locais dos nós do modelo original como
required_knots e defina restrict_to_right_of_required_knots=True ao
chamar automatic_knot_selection(). Isso garante que o AKS só vai adicionar novos
nós aos períodos após os dados originais.
import numpy as np
from meridian.model import knots
from meridian.model import model
from meridian.model import spec
# `data` is an `InputData` object; same as what will be passed to
# `model.Meridian`
aks = knots.AKS(data)
# Use knots selected from a previous model run as required knots and
# automatically select knots located after the last knot
previous_knots = np.array([10, 30, 50, 70, 90])
knot_locations = aks.automatic_knot_selection(
required_knots=previous_knots,
restrict_to_right_of_required_knots=True
).knots
# You must use the 'knots' argument and NOT set 'enable_aks=True'.
model_spec = spec.ModelSpec(knots=knot_locations)
# `input_data` argument is the same `data` passed to `knots.AKS(data)`
mmm = model.Meridian(input_data=data, model_spec=model_spec)
Escolher nós manualmente
Em alguns casos, os usuários preferem definir nós manualmente para a MMM. Esta seção traz algumas orientações básicas sobre como escolher manualmente as posições dos nós.
Ao pensar em como definir manualmente knots de ModelSpec, considere
os dois extremos: os nós podem variar de um até o número de
períodos (n_times). No caso de knots = n_times, não há redução de dimensionalidade,
e cada período recebe o próprio parâmetro. Em um modelo geográfico,
é possível ter o mesmo número de nós e períodos, já que você tem várias
regiões geográficas e, portanto, diversas observações por período. No caso de knots = 1, todos os períodos são medidos com um único parâmetro, o que equivale a dizer que o tempo não tem efeito. Essa ausência de efeito se torna uma intercepto comum para todos os períodos.
No caso de 1 < knots < n_times, você está no meio desses dois extremos. É possível testar um intervalo de valores que abrange o espaço de valores qualificados. Para saber como definir o meio desses dois extremos, acesse Compensação de viés-variância.
Recomendamos tentar o seguinte:
Os modelos geográficos precisam começar pelo padrão (
knots = n_times). Se você perceber que o overfitting é extremo ou que as estimativas de efeito da mídia não são realistas, reduza o número de nós. A necessidade dessa redução fica mais evidente à medida que o número de regiões geográficas por ponto de tempo diminui.Os modelos nacionais devem começar pelo nó
1padrão e, a partir daí, aumentar o número de nós. Continue aumentando até que o overfitting fique extremo ou as estimativas de efeito da mídia se tornem irreais.Um número semelhante de nós pode retornar resultados parecidos, como
knots = 10eknots = 11. Por isso, é recomendável distribuir os valores que você quer usar.
Por exemplo, para definir manualmente 10 nós com espaçamento uniforme:
from meridian.model import model
from meridian.model import spec
model_spec = spec.ModelSpec(knots=10)
mmm = model.Meridian(input_data=data, model_spec=model_spec)
Como alternativa, para especificar manualmente os locais exatos dos nós:
from meridian.model import model
from meridian.model import spec
model_spec = spec.ModelSpec(knots=[7, 14, 30, 37, 44, 60, 67, 74, 90])
mmm = model.Meridian(input_data=data, model_spec=model_spec)
Compensação de viés-variância
Pense na definição do número de nós como uma compensação de viés-variância. No caso de knots = n_times, cada período recebe um parâmetro próprio. Sendo assim, o efeito de um determinado período é estimado usando apenas dados desse intervalo. No entanto, knots = n_times tem alta variação devido ao número menor de pontos de dados disponíveis em um determinado período.
No caso de knots < n_times, cada nó é estimado usando os dados de períodos próximos. Quanto maior a proximidade, maior a ponderação. Como os dois nós mais próximos determinam a inferência de um período específico, o efeito de um período é estimado pelos dados dele mesmo e de períodos próximos. À medida que a quantidade de nós diminui, os pontos de tempo próximos passam a influenciar mais a inferência de um determinado ponto de tempo, e aqueles mais próximos têm uma ponderação maior. Isso reduz a variância porque mais pontos de tempo são usados para estimar o efeito de um determinado período. No entanto, os dados não são do período em questão, o que aumenta o viés.
Em resumo, mais nós reduzem o viés nas estimativas de efeitos temporais, e um número menor de nós diminui a variação nessas estimativas. Como analista, você pode ajustar a compensação de viés-variância. Se o tempo for uma variável de confusão importante entre a mídia e o KPI, a compensação de viés-variância nas estimativas de efeitos temporais vai causar o mesmo efeito nas estimativas de efeitos causais.
Além disso, é possível escolher diferentes compensações de viés-variância para regiões de tempo distintas. Basta definir knots como uma lista, que especifica os locais dos nós. Esses locais podem ser densos em áreas onde você prefere baixo viés nas estimativas (como nas festas de fim de ano) e raros onde o analista prefere baixa variância (como em outras épocas do ano).
Quando é recomendado usar menos nós
Ao definir o número de nós, pense também em como o período afeta a execução da mídia. As variáveis de controle precisam ser variáveis de confusão que afetam tanto a execução da mídia quanto o KPI. Para mais informações, consulte Selecionar variáveis de controle.
O mesmo serve para o tempo. Se o período não for um fator para a execução da mídia, ele não será uma variável de confusão real. Assim, você evita usar muitos graus de liberdade na modelagem de tempo com muitos nós. Os anunciantes precisam definir se o período é importante no planejamento da execução de mídia. Por exemplo, o planejamento de mídia de uma marca de viagens provavelmente depende do período. Já uma marca de lanches pode ter um planejamento mais consistente em diferentes períodos. Além disso, considere se o tempo é mesmo a variável de confusão importante ou se é o substituto de alguma outra variável que pode ser modelada de forma direta, talvez com menos graus de liberdade. Por exemplo, o tempo foi realmente a variável de confusão que gerou a execução da mídia? Ou foi o número de casos de COVID no país? Os anunciantes conhecem a própria estratégia de planejamento de mídia e têm insights sobre esses tópicos.
Quando usar knots < n_times
Há situações em que você precisa definir knots < n_times. Por exemplo, em um modelo nacional sem várias observações por período e sem graus de liberdade suficientes para cada período ter um parâmetro próprio. É necessário um certo nível de redução de dimensionalidade.
Outro exemplo é quando você precisa incluir uma mídia ou uma variável de controle nacionais. Por definição, as variáveis nacionais mudam com o tempo, mas não com base na região. Essa variável é perfeitamente colinear com o tempo e, portanto, é redundante com um modelo que tem um parâmetro para cada período. Se você definir knots com um valor próximo a n_times, tecnicamente poderá ter um modelo identificável. Porém, ele ainda pode ter uma identificabilidade fraca e causar problemas. Considerando as preocupações quanto à estimativa dos efeitos temporais em um modelo nacional, é ainda mais importante ter controles de alta qualidade em um modelo nacional do que em um modelo geográfico. Para mais informações sobre esses controles, consulte Selecionar variáveis de controle.
Outras abordagens para modelar efeitos temporais: indicadores binários e funções periódicas
É possível criar e inserir indicadores binários ou funções periódicas como variáveis de controle para modelar efeitos temporais no Meridian. Cada uma dessas opções oferece vantagens em diferentes casos.
O Meridian recomenda incluir variáveis de controle que também sejam confundidoras, ou seja, que afetem de maneira causal a execução de mídia e o KPI. Também é recomendado incluir variáveis de controle confundidoras relacionadas a efeitos temporais. Consulte Variáveis de controle para saber mais.
Indicadores binários
Um indicador binário assume o valor 1 quando uma condição é atendida e 0 quando não é. Por exemplo, o valor 1 para indicar todos os períodos em dezembro e 0 caso contrário. No Meridian, esses indicadores podem ser usados como variáveis de controle para modelar efeitos temporais consistentes em um conjunto de períodos e que podem variar por região geográfica. Nós e indicadores binários podem ser usados juntos, mas é preciso ter cuidado com o número total de parâmetros usados na modelagem.
Efeitos consistentes
Um indicador binário pode abranger vários períodos, o que pressupõe que o efeito do KPI (per capita em um modelo geográfico) seja consistente em todos os períodos. Ele usa vários períodos para estimar um efeito consistente, melhorando as estimativas e usando graus de liberdade de forma eficiente, desde que a premissa de um efeito consistente seja razoavelmente correta.
O indicador não afeta períodos fora dos indicados. Por outro lado, colocar um nó em um período específico afeta os períodos vizinhos até o próximo nó adjacente.
Modelar efeitos temporais como consistentes em um conjunto de períodos pode ser interessante para um modelo nacional, no qual impor uma estrutura ajuda a estabilizar as estimativas. Para um modelo geográfico, a flexibilidade de usar muitos nós costuma ser melhor.
Variação geográfica
Quando um indicador binário é usado como uma variável de controle em um modelo geográfico, ele é estimado como tendo um efeito dependente da região. Isso é ideal para eventos em que você espera que o impacto seja diferente por região, como o Super Bowl, que tem um impacto maior na cidade-sede. Já os nós estimam efeitos temporais que não dependem da região geográfica. Eles criam uma função spline flexível para capturar padrões temporais que ocorrem em todas as regiões. Isso os torna mais eficientes em termos de parâmetros, caso você não espere efeitos temporais dependentes da região.
Desativar a variação geográfica para um indicador binário
É possível usar um indicador binário sem efeitos temporais dependentes da região.
Para fazer isso, defina a distribuição a priori da variância hierárquica, xi_c, como uma massa de pontos em zero. Nesse caso, cada coeficiente geográfico para o indicador binário será idêntico. Para desativar os efeitos geográficos de todas as variáveis de controle, defina a distribuição a priori de variância como um valor determinista de zero:
xi_c = tfp.distributions.Deterministic(0)
Para desativar o efeito geográfico em apenas uma variável de controle específica, defina o parâmetro scale da distribuição a priori como zero. Por exemplo, se você tiver quatro variáveis de controle e quiser desativar os efeitos geográficos da primeira:
xi_c = tfp.distributions.HalfNormal(scale=[0, 5, 5, 5])
Risco de multicolinearidade
Os indicadores binários podem ter um risco de alta multicolinearidade com variáveis de execução de mídia. Por isso, é importante prestar atenção à multicolinearidade e incluir apenas indicadores binários que sejam de fato confundidores.
Funções periódicas
Outra opção é adicionar uma função periódica, por exemplo, uma série de Fourier, como uma variável de controle. As funções periódicas podem ser uma alternativa interessante aos nós, principalmente em modelos nacionais.
Elas modelam os efeitos temporais como tendo um padrão suave e cíclico no KPI (KPI per capita no caso de um modelo geográfico) e são uma forte proposição paramétrica sobre como o tempo afeta o KPI. Isso é adequado para modelos nacionais, em que impor uma estrutura ajuda a ter uma estimativa estável de sazonalidade. Para um modelo geográfico, a flexibilidade de usar muitos nós costuma ser melhor, já que não força um padrão suave e cíclico no KPI.
Recomendações práticas
As recomendações dependem se o modelo é geográfico ou nacional.
Modelos geográficos
Os indicadores binários podem ser usados em modelos geográficos para modelar efeitos temporais dependentes da região. Nós e indicadores binários podem ser usados juntos, mas é preciso ter cuidado com o número total de parâmetros usados na modelagem. Indicadores binários com nós completos não são recomendados.
- Para efeitos temporais que não dependem da região geográfica, use nós: se você quiser modelar um padrão temporal consistente em várias regiões, eles oferecem flexibilidade sem risco de parametrização excessiva.
- Para efeitos temporais que são dependentes da região geográfica, use um indicador binário: se você tiver uma hipótese forte de que o impacto de um evento varia de acordo com a região, um indicador binário como variável de controle é a ferramenta certa.
Modelos nacionais
Os modelos nacionais se beneficiam principalmente da parcimônia, que pode ser alcançada com indicadores binários, funções periódicas ou alguns nós bem posicionados. Eles podem ser usados juntos, mas é preciso ter cuidado com o número total de parâmetros, dada a importância da parcimônia em um modelo nacional. Cada uma dessas opções melhora as estimativas e usa graus de liberdade de maneira eficiente, desde que a premissa seja razoavelmente correta. A seguir, resumimos as premissas para cada elemento:
- As funções periódicas modelam os efeitos temporais como tendo um padrão suave e cíclico no KPI.
- Os indicadores binários modelam os efeitos temporais como consistentes em todos os períodos afetados.
- Os nós modelam efeitos temporais como uma tendência linear segmentada ao longo do tempo.