Una campagna email funziona davvero? Come misurare l’effetto causale con Python e DoWhy

Cerca:

Generic selectors
Exact matches only
Search in title
Search in content
Post Type Selectors
inferenza causale campagna email retention con DoWhy e Python

Una campagna email sembra aver prodotto un risultato straordinario.

Dopo l’invio, il 76% dei clienti raggiunti risulta ancora attivo dopo 90 giorni, contro poco più del 54% dei clienti non raggiunti.

La differenza è di oltre 22 punti percentuali.

Il marketing manager potrebbe quindi concludere:

“La campagna ha funzionato. Replichiamola su tutti i clienti.”

Ma questa conclusione potrebbe essere sbagliata.

Il problema è semplice da formulare e molto difficile da risolvere:

i clienti che hanno ricevuto l’email erano davvero comparabili con quelli che non l’hanno ricevuta?

Nel nostro esempio, il team marketing ha coinvolto più spesso clienti Premium e utenti con un engagement già elevato.

Se questi clienti fossero rimasti attivi più spesso anche senza ricevere l’email, il +22,27% osservato nei dati non rappresenterebbe l’effetto della campagna.

Sarebbe invece una combinazione di:

  • caratteristiche iniziali dei clienti;
  • modalità con cui il trattamento è stato assegnato;
  • effetto realmente prodotto dalla campagna.

È qui che entra in gioco l’inferenza causale.

In questo articolo costruiremo una simulazione completa in Python e utilizzeremo DoWhy per rispondere a una domanda molto più utile dal punto di vista aziendale:

Quanto della maggiore retention possiamo attribuire alla campagna, una volta considerate le differenze preesistenti tra i clienti?

L’obiettivo non è trovare semplicemente “il numero giusto”.

È capire quale decisione quel numero permette realmente di prendere.

Pubblicità

Il problema: differenza osservata o effetto causale?

Immaginiamo una piattaforma SaaS con 12.000 clienti.

Il marketing team vuole aumentare la retention nei successivi 90 giorni e decide di inviare una campagna email.

L’assegnazione, però, non è casuale.

Per ragioni commerciali, il team tende a coinvolgere:

  • clienti Premium;
  • clienti con elevato engagement;
  • clienti considerati particolarmente interessanti dal punto di vista commerciale.

Dal punto di vista operativo è perfettamente plausibile.

Dal punto di vista statistico crea però un problema.

Se confrontiamo direttamente:

[math]P(Y=1 \mid T=1)[/math]

con

[math]P(Y=1 \mid T=0)[/math]

stiamo confrontando due gruppi che potrebbero essere diversi prima ancora della campagna.

Le variabili del nostro esempio

Variabile Significato
email 1 se il cliente riceve la campagna, 0 altrimenti
retained 1 se il cliente è ancora attivo dopo 90 giorni
segment_premium 1 se il cliente appartiene al segmento Premium
engagement livello di attività osservato prima della campagna

La collocazione temporale è fondamentale.

segment_premium ed engagement sono caratteristiche pre-trattamento.

Questo significa che esistono prima dell’email e possono influenzare sia la probabilità di ricevere il trattamento sia la probabilità di rimanere clienti.

Non dobbiamo invece controllare automaticamente ogni variabile disponibile nel dataset.

Una variabile successiva all’email potrebbe essere un mediatore del trattamento. Controllarla potrebbe significare eliminare proprio una parte dell’effetto che vogliamo misurare.


La prima misura: +22,27 punti percentuali

Cominciamo dall’analisi più semplice.

Calcoliamo la differenza tra la retention dei clienti trattati e quella dei clienti non trattati:

[math]\displaystyle \Delta_{naive} = P(retained=1 \mid email=1) – P(retained=1 \mid email=0)[/math]

Nella simulazione otteniamo:

[math]\Delta_{naive} = 0{,}2227[/math]

cioè:

+22,27 punti percentuali

È un risultato enorme.

Ma cosa ci sta realmente dicendo?

La differenza osservata risponde alla domanda:

“Quanto differisce la retention osservata tra i due gruppi?”

Non risponde necessariamente alla domanda:

“Quanto sarebbe cambiata la retention di questi stessi clienti se non avessero ricevuto l’email?”

La seconda è una domanda causale.

Questa distinzione è il cuore dell’intero articolo.

Pubblicità

Associazione non significa causalità

Supponiamo di osservare:

  • 76% di retention tra i destinatari;
  • 54% tra i non destinatari.

Possiamo certamente dire:

I clienti che hanno ricevuto l’email hanno avuto una retention maggiore.

Non possiamo però concludere automaticamente:

L’email ha aumentato la retention di 22,27 punti percentuali.

Per capire perché, immaginiamo due scenari.

Scenario A: l’email funziona

L’email modifica realmente il comportamento del cliente.

Senza email:

[math]P(retained) = 0{,}60[/math]

Con email:

[math]P(retained) = 0{,}67[/math]

L’effetto causale sarebbe circa:

[math]+7 \text{ pp}[/math]

Scenario B: l’email non funziona

Supponiamo invece che i clienti più fedeli ricevano più frequentemente l’email.

I clienti ad alto engagement hanno una maggiore probabilità di ricevere il trattamento e, indipendentemente dalla campagna, una maggiore probabilità di rimanere attivi.

Potremmo quindi osservare:

[math]Retention_{email} > Retention_{no \ email}[/math]

anche se:

[math]Effect_{email} = 0[/math]

Questa è la situazione classica del confondimento.


Il confondimento

Nel nostro esempio abbiamo due variabili fondamentali:

  • segment_premium;
  • engagement.

Entrambe possono influenzare la probabilità di ricevere l’email.

Ma entrambe possono anche influenzare la retention.

Possiamo rappresentare il processo attraverso un DAG, Directed Acyclic Graph:

segment_premium ─────→ email ─────→ retained
       │                 ↑
       │                 │
       └────→ engagement ┘
       │          │
       └──────────┴────────────→ retained

I percorsi problematici sono:

email ← segment_premium → retained

email ← engagement → retained

Sono backdoor paths.

Una parte dell’associazione tra email e retention può quindi essere spiegata da variabili che precedono il trattamento.

Nel nostro modello assumiamo che:

[math]Z = \{segment\_premium, engagement\}[/math]

sia sufficiente per bloccare i principali percorsi di confondimento osservati.

Questa però è un’assunzione causale, non un fatto che DoWhy possa dimostrare automaticamente.


Il DAG non è un disegno decorativo

Questo è uno dei concetti più importanti dell’inferenza causale.

Un errore frequente consiste nel pensare:

“Faccio girare DoWhy e sarà il software a dirmi quali variabili controllare.”

Il processo corretto è invece:

  1. comprendere il processo aziendale;
  2. identificare le variabili che precedono il trattamento;
  3. formulare un modello causale;
  4. rappresentarlo con un DAG;
  5. individuare i percorsi di confondimento;
  6. determinare un set di aggiustamento;
  7. scegliere il metodo di stima;
  8. verificare quanto le conclusioni siano robuste.

DoWhy può formalizzare e implementare questo workflow.

Non può però stabilire autonomamente se la nostra rappresentazione del business sia corretta.

In altre parole:

la qualità dell’inferenza causale dipende dalle assunzioni sul processo che genera i dati, non soltanto dall’algoritmo utilizzato.

La documentazione di DoWhy stessa struttura l’analisi intorno a identificazione, stima e successiva verifica dell’effetto.


Il problema controfattuale

Per capire veramente la causalità dobbiamo introdurre il concetto di controfattuale.

Per ogni cliente immaginiamo due possibili risultati.

[math]Y(1)[/math]

è la retention che osserveremmo se il cliente ricevesse l’email.

[math]Y(0)[/math]

è la retention che osserveremmo se lo stesso cliente non ricevesse l’email.

L’effetto individuale sarebbe:

[math]Y(1) – Y(0)[/math]

Ed ecco il problema fondamentale.

Per uno stesso cliente possiamo osservare soltanto uno dei due risultati.

Se riceve l’email osserviamo:

[math]Y(1)[/math]

ma non possiamo osservare contemporaneamente:

[math]Y(0)[/math]

Il risultato mancante è proprio il controfattuale.

L’inferenza causale cerca di ricostruire questo confronto utilizzando informazioni sugli altri clienti e facendo determinate assunzioni sul processo di assegnazione del trattamento.

Nel nostro caso vogliamo stimare l’Average Treatment Effect, ATE:

[math]ATE = E[Y(1) – Y(0)][/math]

L’ATE risponde alla domanda:

“Qual è la variazione media della retention se trattassimo i clienti invece di non trattarli?”


Tre modi diversi di affrontare il problema

A questo punto possiamo confrontare tre famiglie di approcci.

Metodo Domanda principale
Differenza osservata Quanto differiscono i gruppi?
Modello di outcome Qual è l’effetto dopo aver considerato le covariate?
Propensity score Come rendere più comparabili trattati e controlli?

Nessuno di questi metodi elimina automaticamente tutte le fonti di bias.

Tutti dipendono dalla qualità delle variabili osservate e dalle assunzioni causali.


1. Regressione logistica

Poiché retained è una variabile binaria, possiamo utilizzare una regressione logistica:

[math]\displaystyle logit(P(retained=1)) = \beta_0 + \beta_1 email + \beta_2 Premium + \beta_3 Engagement[/math]

La regressione non confronta semplicemente tutti i destinatari con tutti i non destinatari.

Tiene conto delle caratteristiche osservate dei clienti.

Per trasformare il modello in una quantità interpretabile in termini di probabilità, possiamo calcolare l’Average Marginal Effect dell’email.

Per ogni cliente stimiamo:

[math]\hat P(Y=1 \mid email=1, X)[/math]

e:

[math]\hat P(Y=1 \mid email=0, X)[/math]

mantenendo invariato il resto delle caratteristiche.

Poi calcoliamo la differenza media.

Questo produce una misura direttamente interpretabile in punti percentuali.

Nel dataset simulato il risultato è nell’ordine di 5–6 punti percentuali, molto lontano dai 22,27 pp della differenza grezza.

Questo è il primo segnale che il confronto iniziale era fortemente influenzato dalla composizione dei gruppi.

Ma non dobbiamo ancora dire:

“5,6 pp è il vero effetto.”

È una stima dipendente dal modello.


2. Propensity score

Un approccio diverso consiste nel modellare la probabilità che un cliente riceva l’email.

Definiamo il propensity score:

[math]e(X) = P(email=1 \mid X)[/math]

dove:

[math]X = \{segment\_premium, engagement\}[/math]

Un cliente Premium con engagement elevato potrebbe avere una probabilità molto alta di ricevere l’email.

Un cliente non Premium con engagement basso potrebbe avere una probabilità molto più bassa.

Confrontare direttamente questi due clienti sarebbe poco informativo.

Il propensity score cerca invece di costruire confronti tra unità con caratteristiche osservate più simili.

DoWhy supporta diversi metodi basati sul propensity score, tra cui stratification, matching e weighting.


3. Propensity score stratification

Con la stratification dividiamo i clienti in gruppi con propensity score simili.

All’interno di ciascuno strato confrontiamo:

  • clienti trattati;
  • clienti non trattati.

La domanda diventa:

“Tra clienti con probabilità simile di ricevere la campagna, quale differenza di retention osserviamo?”

Nella simulazione ci aspettiamo una stima vicina all’ordine di grandezza dell’ATE di riferimento, cioè circa 6–7 punti percentuali.

La cosa importante non è però scegliere automaticamente la stima più alta.

È verificare se il metodo sta realmente costruendo gruppi comparabili.


4. Propensity score matching

Nel matching cerchiamo clienti trattati e non trattati comparabili sulla base delle covariate e del propensity score.

L’idea intuitiva è:

per ogni cliente trattato cerchiamo uno o più clienti non trattati che gli assomiglino.

Se il matching è ben costruito, il confronto diventa più credibile.

Ma attenzione:

matching non significa automaticamente causalità.

La qualità del risultato dipende, tra le altre cose, da:

  • scelta delle covariate;
  • qualità del propensity model;
  • disponibilità di comparatori;
  • definizione della distanza;
  • eventuale caliper;
  • overlap;
  • bilanciamento ottenuto dopo il matching.
Forse potrebbe interessarti anche:  Pandas in Azienda: 3 Esercizi Pratici per Pulire Dati e Creare Report

Prima di stimare: controlliamo l’overlap

Questa è una verifica che spesso viene dimenticata.

Immaginiamo che quasi tutti i clienti Premium ricevano l’email.

Potremmo avere:

Propensity score

Controlli    ███████████████

Trattati                       ███████████████

In questo caso esiste una regione in cui abbiamo praticamente soltanto trattati.

Non possiamo costruire un controfattuale credibile per clienti che non hanno comparatori simili.

Questa condizione è legata alla positivity, o overlap.

Prima di interpretare una stima causale dobbiamo quindi controllare:

  • distribuzione dei propensity score;
  • sovrapposizione tra trattati e controlli;
  • numerosità degli strati;
  • osservazioni escluse;
  • presenza di aree del covariate space prive di comparatori.

La domanda diventa:

“Per quali clienti abbiamo davvero informazioni sufficienti per stimare un effetto causale?”

Questa è una domanda molto più importante di:

“Quale algoritmo produce l’ATE più bello?”


Balance check: abbiamo davvero reso i gruppi comparabili?

Un propensity score non dovrebbe essere valutato soltanto guardando il valore dell’ATE.

Dobbiamo anche controllare il bilanciamento delle covariate.

Uno degli strumenti più comuni è la Standardized Mean Difference, SMD.

Per una covariata (X):

[math]\displaystyle SMD = \frac{\bar X_T – \bar X_C}{\sqrt{(s_T^2 + s_C^2)/2}}[/math]

L’obiettivo è ridurre le differenze tra trattati e controlli dopo l’aggiustamento.

Una diagnostica di questo tipo è fondamentale perché permette di distinguere:

“abbiamo applicato il matching”

da:

“il matching ha effettivamente migliorato la comparabilità dei gruppi.”


Il riferimento che conosciamo solo perché stiamo simulando

Qui la simulazione diventa particolarmente utile.

In un dataset aziendale reale non conosciamo l’effetto causale vero.

Nella nostra simulazione, invece, conosciamo il meccanismo generativo.

La retention viene generata da:

[math]\displaystyle logit(P(Y=1)) = -1,15 + 1,50 Premium + 2,20 Engagement + 0,35 Email[/math]

Il coefficiente dell’email è inserito nel logit, non direttamente nella probabilità.

Questo è importante.

Non possiamo dire:

“0,35 significa +35 punti percentuali.”

L’effetto sulla probabilità dipende infatti dal livello delle altre variabili.

Possiamo invece calcolare, per ogni cliente, le due probabilità potenziali:

[math]P(Y=1 \mid email=1, X)[/math]

e:

[math]P(Y=1 \mid email=0, X)[/math]

e poi fare la media delle differenze:

[math]\displaystyle ATE_{sim} = \frac{1}{N} \sum_{i=1}^{N} [P_i(Y=1 \mid email=1) – P_i(Y=1 \mid email=0)][/math]

Con il seed utilizzato nell’esempio otteniamo circa:

[math]ATE_{sim} \approx 0{,}0685[/math]

cioè:

+6,85 punti percentuali

Questo è il nostro ATE di riferimento della simulazione.

Non sarebbe disponibile in un vero progetto aziendale.

Lo conosciamo perché abbiamo costruito noi il processo che genera i dati.

È proprio questo che rende la simulazione didatticamente interessante: possiamo verificare quanto i diversi metodi riescano a recuperare un effetto che, nel mondo simulato, conosciamo.

Pubblicità

Il confronto diventa interessante

Possiamo quindi sintetizzare il problema:

Analisi Interpretazione
Differenza osservata +22,27 pp
Regressione logistica circa 5–6 pp
Propensity score circa 5–7 pp, a seconda dell’estimatore
ATE di riferimento della simulazione +6,85 pp

Il messaggio non è:

“6,59 è giusto e 5,58 è sbagliato.”

Il messaggio è diverso.

I metodi di aggiustamento portano l’analisi verso un ordine di grandezza molto distante dal confronto grezzo.

Questo mostra concretamente quanto il confondimento possa alterare una conclusione aziendale.


Ma attenzione: non abbiamo dimostrato la causalità

Questo è un passaggio che merita di essere sottolineato.

Supponiamo di ottenere:

[math]ATE = 0{,}0659[/math]

Non significa:

“Abbiamo dimostrato matematicamente che l’email causa un aumento del 6,59%.”

Significa:

“Sotto le assunzioni causali del nostro modello e dato il metodo utilizzato, stimiamo un effetto medio di circa 6,59 punti percentuali.”

La differenza è fondamentale.

Un modello causale osservazionale dipende da ipotesi come:

  • corretto set di confondenti;
  • assenza di importanti confondenti non osservati;
  • corretta definizione del trattamento;
  • corretta misurazione delle variabili;
  • positivity;
  • corretta specificazione dell’estimatore.

DoWhy aiuta a rendere esplicite queste assunzioni, ma non può trasformare automaticamente dati osservazionali in un esperimento.


Il problema del confondente che non osserviamo

Immaginiamo una variabile:

customer_intent

che misura quanto il cliente sia realmente intenzionato a rinnovare l’abbonamento.

Supponiamo che:

customer_intent → email
customer_intent → retained

Il problema è che questa variabile non compare nel dataset.

Rimane quindi aperto il percorso:

email ← customer_intent → retained

La regressione non può controllarlo.

Il propensity score non può controllarlo.

Il matching non può controllarlo.

DoWhy non può inventarlo.

Questa è una delle regole fondamentali dell’inferenza causale:

un algoritmo può correggere il confondimento che abbiamo osservato e modellato; non può eliminare automaticamente ciò che non sappiamo di dover controllare.

Per questo la qualità dei dati e la conoscenza del processo aziendale sono parte integrante dell’analisi causale.


Cosa succede se dimentichiamo Premium?

Possiamo simulare un errore molto comune.

Supponiamo di controllare engagement, ma non segment_premium.

Il modello diventa:

[math]\displaystyle logit(P(Y=1)) = \beta_0 + \beta_1 Email + \beta_2 Engagement[/math]

La stima dell’effetto può aumentare sensibilmente rispetto al modello completo.

Nella simulazione originale il risultato passa indicativamente da circa:

[math]+5{,}6 \text{ pp}[/math]

a:

[math]+12{,}3 \text{ pp}[/math]

Non dobbiamo però interpretare la differenza:

[math]12{,}3 – 5{,}6 = 6{,}7 \text{ pp}[/math]

come una misura universale del bias da omissione.

È semplicemente il risultato prodotto da questa simulazione.

Il vero insegnamento è un altro:

una variabile confondente importante può cambiare radicalmente la conclusione dell’analisi.


Refutation: una stima robusta dovrebbe sopravvivere a perturbazioni ragionevoli

Una volta ottenuta una stima, possiamo chiederci:

“Quanto è sensibile il risultato a piccole modifiche del dataset o del trattamento?”

DoWhy mette a disposizione diversi refutation tests, tra cui:

  • placebo treatment;
  • random common cause;
  • data subset;
  • altri controlli di robustezza.

La documentazione DoWhy presenta i refutation test proprio come strumenti per mettere alla prova la stabilità dell’analisi, non come una prova definitiva della causalità.

Placebo treatment

Sostituiamo il trattamento reale con un trattamento casuale.

Se il metodo è ragionevole, il trattamento placebo non dovrebbe produrre un grande effetto sistematico.

Un risultato vicino a zero è quindi coerente con ciò che ci aspettiamo.

Ma attenzione:

un placebo test positivo non dimostra che l’effetto originale sia causale.

Dice soltanto che l’analisi non sembra generare automaticamente un grande effetto quando il trattamento causale viene sostituito con uno placebo.


Random common cause

Possiamo aggiungere una causa comune generata casualmente.

Se l’effetto stimato rimane sostanzialmente stabile, questo è un comportamento rassicurante.

Ancora una volta, però:

non è una dimostrazione di correttezza.

È un controllo di robustezza.


Data subset

Possiamo anche ripetere l’analisi su un sottoinsieme casuale dei dati.

Se la stima rimane relativamente vicina a quella originale, abbiamo un’altra evidenza di stabilità.

L’obiettivo complessivo dei refutation test è quindi:

[math]\text{stima} \rightarrow \text{perturbazione} \rightarrow \text{nuova stima}[/math]

e osservare quanto il risultato cambi.


La parte che interessa davvero al manager: quanto vale la campagna?

Arriviamo alla decisione.

Supponiamo che:

  • clienti trattati: 4.000;
  • valore netto incrementale medio per cliente trattenuto: €513,33;
  • costo complessivo della campagna: €98.700.

Il valore di €513,33 deve essere interpretato come valore netto incrementale, non come semplice ricavo medio.

Consideriamo uno scenario prudenziale con:

[math]uplift = 5\%[/math]

I clienti trattenuti aggiuntivi attesi sono:

[math]4000 \times 0{,}05 = 200[/math]

Il valore economico incrementale è:

[math]\displaystyle 200 \times 513{,}33 = €102.666[/math]

Sottraendo il costo:

[math]\displaystyle €102.666 – €98.700 = €3.966[/math]

Il ritorno netto stimato è quindi:

circa €3.966

La campagna è positiva, ma soltanto di poco.

👉 L’inferenza causale al colloquio di lavoro: Guida avanzata per professionisti


E se usassimo erroneamente il +22,27%?

Ora vediamo perché confondere associazione e causalità può essere economicamente pericoloso.

Se utilizzassimo il +22,27% come se fosse l’uplift incrementale:

[math]4000 \times 0{,}2227 \times 513{,}33 – 98.700[/math]

otterremmo circa:

€358.600 di ritorno netto

Il confronto è impressionante:

Scenario Uplift Ritorno netto
Differenza osservata 22,27 pp ≈ €358.600
Scenario prudenziale 5 pp ≈ €3.966

Non stiamo parlando di un piccolo errore statistico.

Stiamo parlando di una differenza che può cambiare completamente una decisione di investimento.


Il break-even: qual è l’uplift minimo necessario?

Possiamo rovesciare il problema.

Vogliamo sapere quale uplift rende la campagna economicamente neutrale.

Poniamo:

[math]N \times uplift \times V – C = 0[/math]

Da cui:

[math]\displaystyle uplift_{BE} = \frac{C}{N \times V}[/math]

Con:

[math]C = 98.700[/math]

[math]N = 4.000[/math]

[math]V = 513{,}33[/math]

otteniamo:

[math]uplift_{BE} \approx 4{,}81\%[/math]

Quindi la campagna deve produrre almeno:

+4,81 punti percentuali di uplift

per raggiungere il break-even.

Questa è una domanda manageriale molto più interessante di:

“La campagna è statisticamente significativa?”

La domanda diventa:

“Quanto è plausibile che l’effetto causale superi il 4,81%?”


Significatività statistica ≠ convenienza economica

Una campagna può essere:

  • statisticamente significativa ma economicamente poco interessante;
  • economicamente interessante ma ancora troppo incerta;
  • statisticamente non conclusiva perché il campione è piccolo;
  • apparentemente molto efficace ma fortemente distorta dal confondimento.

Per questo un dashboard manageriale dovrebbe riportare almeno:

  1. stima dell’effetto;
  2. intervallo di confidenza;
  3. numero di clienti trattati;
  4. costo dell’intervento;
  5. valore netto per cliente incrementale;
  6. break-even uplift;
  7. durata dell’effetto;
  8. eventuali condizioni necessarie perché l’effetto sia identificabile.

La domanda finale non è:

[math]ATE = 6{,}59\%[/math]

ma:

[math]P(ATE > uplift_{BE})[/math]

o, più semplicemente:

“Quanto siamo sicuri che l’effetto sia abbastanza grande da rendere conveniente l’investimento?”

Questo è il passaggio dalla statistica alla decision intelligence.


L’ATE non dice che l’email funziona allo stesso modo per tutti

C’è un’altra questione importante.

L’ATE è una media.

Potremmo avere:

  • effetto quasi nullo sui clienti Premium;
  • effetto molto più alto sui clienti Standard;
  • effetto negativo su alcuni segmenti;
  • effetto positivo su altri.

In questo caso l’ATE complessivo potrebbe nascondere informazioni molto importanti.

Possiamo introdurre il Conditional Average Treatment Effect, CATE:

[math]CATE(x) = E[Y(1) – Y(0) \mid X = x][/math]

La domanda diventa:

“Per quali clienti la campagna funziona davvero?”

Questo apre la porta a una forma più avanzata di marketing analytics:

Forse potrebbe interessarti anche:  Esercizio MANOVA Svolto: Analisi Multivariata su Sentiment e Rating App

non soltanto prevedere chi comprerà, ma stimare chi comprerà grazie all’intervento.

È una distinzione fondamentale.

Un modello predittivo cerca clienti con alta probabilità di conversione.

Un modello causale cerca clienti per i quali l’intervento modifica realmente la probabilità di conversione.


Il vero riferimento: l’esperimento randomizzato

A questo punto emerge una conclusione importante.

Se possiamo progettare la prossima campagna, spesso non abbiamo bisogno di costruire un sistema causale osservazionale estremamente sofisticato.

Possiamo fare qualcosa di più semplice:

                 Clienti
                    │
          ┌─────────┴─────────┐
          │                   │
          ▼                   ▼
       Email              Controllo

Assegniamo casualmente i clienti ai due gruppi.

Questo è un randomized controlled trial, o più semplicemente un A/B test.

La randomizzazione tende a rendere i gruppi comparabili anche rispetto a caratteristiche che non abbiamo osservato.

La domanda diventa:

“Tra clienti assegnati casualmente all’email e clienti assegnati casualmente al controllo, quale differenza osserviamo nella retention?”

Quando è tecnicamente, eticamente e operativamente possibile, questo approccio è generalmente il riferimento più diretto per misurare l’incrementalità.

L’inferenza causale osservazionale rimane invece fondamentale quando:

  • l’esperimento non è stato progettato;
  • non possiamo randomizzare;
  • il trattamento è già avvenuto;
  • la randomizzazione è troppo costosa;
  • esistono vincoli etici o operativi.

La lezione è quindi paradossale ma importante:

il modo migliore per fare causal inference spesso è progettare meglio i dati prima ancora di analizzarli.

 

Pubblicità

Il codice Python

Il seguente script costruisce il dataset simulato, calcola la differenza osservata, stima una regressione logistica, costruisce il DAG e utilizza DoWhy per identificare e stimare l’effetto causale.

DoWhy supporta esplicitamente estimatori basati su propensity score, regressione e altri approcci di stima backdoor.

Nota: Se compare un warning su pygraphviz, ignorarlo: DoWhy usa pydot come fallback.

import numpy as np
import pandas as pd
import statsmodels.api as sm

from dowhy import CausalModel


# ============================================================
# 1. RIPRODUCIBILITÀ
# ============================================================

RANDOM_SEED = 42
np.random.seed(RANDOM_SEED)

N = 12_000


# ============================================================
# 2. VARIABILI PRE-TRATTAMENTO
# ============================================================

segment_premium = np.random.binomial(
    1,
    0.30,
    size=N
)

engagement = np.clip(
    np.random.normal(
        loc=0.55 + 0.20 * segment_premium,
        scale=0.18,
        size=N
    ),
    0,
    1
)


# ============================================================
# 3. ASSEGNAZIONE NON CASUALE DEL TRATTAMENTO
# ============================================================

logit_treatment = (
    -2.0
    + 1.8 * segment_premium
    + 3.0 * engagement
)

p_email = 1 / (1 + np.exp(-logit_treatment))

email = np.random.binomial(
    1,
    p_email
)


# ============================================================
# 4. GENERAZIONE DELLA RETENTION
# ============================================================

logit_retention = (
    -1.15
    + 1.50 * segment_premium
    + 2.20 * engagement
    + 0.35 * email
)

p_retention = 1 / (
    1 + np.exp(-logit_retention)
)

retained = np.random.binomial(
    1,
    p_retention
)


# ============================================================
# 5. DATASET
# ============================================================

df = pd.DataFrame({
    "email": email,
    "retained": retained,
    "segment_premium": segment_premium,
    "engagement": engagement
})


# ============================================================
# 6. DIFFERENZA OSSERVATA
# ============================================================

retention_treated = df.loc[
    df["email"] == 1,
    "retained"
].mean()

retention_control = df.loc[
    df["email"] == 0,
    "retained"
].mean()

naive_effect = (
    retention_treated
    - retention_control
)

print(
    f"Retention trattati: {retention_treated:.4f}"
)

print(
    f"Retention controllo: {retention_control:.4f}"
)

print(
    f"Differenza osservata: {naive_effect:.4f}"
)


# ============================================================
# 7. REGRESSIONE LOGISTICA
# ============================================================

X = sm.add_constant(
    df[
        [
            "email",
            "segment_premium",
            "engagement"
        ]
    ]
)

y = df["retained"]

logit_model = sm.Logit(
    y,
    X
).fit(
    disp=False
)

print(logit_model.summary())


# ============================================================
# 8. AVERAGE MARGINAL EFFECT
# ============================================================

X1 = X.copy()
X0 = X.copy()

X1["email"] = 1
X0["email"] = 0

predicted_1 = logit_model.predict(X1)
predicted_0 = logit_model.predict(X0)

marginal_effect = (
    predicted_1 - predicted_0
).mean()

print(
    f"AME email: {marginal_effect:.4f}"
)


# ============================================================
# 9. DAG
# ============================================================

graph = """
digraph {
    segment_premium -> engagement;
    segment_premium -> email;
    segment_premium -> retained;
    engagement -> email;
    engagement -> retained;
    email -> retained;
}
"""


# ============================================================
# 10. MODELLO CAUSALE
# ============================================================

causal_model = CausalModel(
    data=df,
    treatment="email",
    outcome="retained",
    graph=graph
)


# ============================================================
# 11. IDENTIFICAZIONE
# ============================================================

identified_estimand = (
    causal_model.identify_effect()
)

print(identified_estimand)


# ============================================================
# 12. PROPENSITY SCORE STRATIFICATION
# ============================================================

estimate_stratification = (
    causal_model.estimate_effect(
        identified_estimand,
        method_name=(
            "backdoor."
            "propensity_score_stratification"
        ),
        target_units="ate",
        confidence_intervals=True
    )
)

print(
    "ATE stratification:",
    estimate_stratification.value
)


# ============================================================
# 13. PROPENSITY SCORE MATCHING
# ============================================================

estimate_matching = (
    causal_model.estimate_effect(
        identified_estimand,
        method_name=(
            "backdoor."
            "propensity_score_matching"
        ),
        target_units="ate",
        confidence_intervals=True
    )
)

print(
    "ATE matching:",
    estimate_matching.value
)


# ============================================================
# 14. ATE DI RIFERIMENTO DELLA SIMULAZIONE
# ============================================================

logit_y1 = (
    -1.15
    + 1.50 * segment_premium
    + 2.20 * engagement
    + 0.35
)

logit_y0 = (
    -1.15
    + 1.50 * segment_premium
    + 2.20 * engagement
)

p_y1 = 1 / (
    1 + np.exp(-logit_y1)
)

p_y0 = 1 / (
    1 + np.exp(-logit_y0)
)

reference_ate = (
    p_y1 - p_y0
).mean()

print(
    f"ATE di riferimento simulazione: "
    f"{reference_ate:.4f}"
)

Retention trattati: 0.7508
Retention controllo: 0.5281
Differenza osservata: 0.2227
ERROR:dowhy.causal_graph:Error: Pygraphviz cannot be loaded. No module named ‘pygraphviz’
Trying pydot …
Logit Regression Results
==============================================================================
Dep. Variable: retained No. Observations: 12000
Model: Logit Df Residuals: 11996
Method: MLE Df Model: 3
Date: Fri, 04 Sep 2026 Pseudo R-squ.: 0.1275
Time: 09:38:35 Log-Likelihood: -6779.0
converged: True LL-Null: -7770.0
Covariance Type: nonrobust LLR p-value: 0.000
===================================================================================
coef std err z P>|z| [0.025 0.975]
———————————————————————————–
const -1.2204 0.070 -17.530 0.000 -1.357 -1.084
email 0.2837 0.045 6.333 0.000 0.196 0.371
segment_premium 1.3882 0.064 21.694 0.000 1.263 1.514
engagement 2.3813 0.124 19.224 0.000 2.138 2.624
===================================================================================
AME email: 0.0558
Estimand type: EstimandType.NONPARAMETRIC_ATE

### Estimand : 1
Estimand name: backdoor
Estimand expression:
d
────────(E[retained|engagement,segmentₚᵣₑₘᵢᵤₘ])
d[email]
Estimand assumption 1, Unconfoundedness: If U→{email} and U→retained then P(retained|email,engagement,segment_premium,U) = P(retained|email,engagement,segment_premium)

### Estimand : 2
Estimand name: iv
No such variable(s) found!

### Estimand : 3
Estimand name: frontdoor
No such variable(s) found!

### Estimand : 4
Estimand name: general_adjustment
Estimand expression:
d
────────(E[retained|engagement,segmentₚᵣₑₘᵢᵤₘ])
d[email]
Estimand assumption 1, Unconfoundedness: If U→{email} and U→retained then P(retained|email,engagement,segment_premium,U) = P(retained|email,engagement,segment_premium)

ATE stratification: 0.06591687222098927
ATE matching: 0.05416666666666667
ATE di riferimento simulazione: 0.0685

Commento applicativo e manageriale

L’output mostra perché una campagna non dovrebbe essere valutata osservando soltanto la retention dei destinatari. Nel nostro caso, il 75,08% dei clienti trattati è rimasto attivo dopo 90 giorni, contro il 52,81% dei clienti non trattati. La differenza osservata è quindi di 22,27 punti percentuali. Questo dato è reale dal punto di vista descrittivo, ma non può essere interpretato automaticamente come incremento prodotto dall’email: i clienti raggiunti erano più spesso Premium e presentavano livelli di engagement differenti già prima dell’invio.

Quando introduciamo queste caratteristiche nella regressione logistica, l’effetto marginale medio dell’email scende a 5,58 punti percentuali. Dal punto di vista manageriale, la lettura cambia radicalmente: non possiamo dire che l’email abbia trattenuto 22 clienti aggiuntivi ogni 100 destinatari; possiamo dire che, sotto le assunzioni del modello causale, l’incremento plausibilmente attribuibile alla campagna è nell’ordine di 5–6 clienti aggiuntivi ogni 100. La differenza rimanente riflette soprattutto la composizione dei gruppi e il fatto che i clienti trattati erano, in parte, già più predisposti a rimanere.

Indicatore Lettura manageriale
Retention trattati: 75,08% Risultato osservato tra i destinatari.
Retention controllo: 52,81% Risultato osservato tra i non destinatari.
Differenza osservata: +22,27 pp Non equivale automaticamente all’incrementalità.
AME dell’email: +5,58 pp Incremento medio stimato dopo l’aggiustamento.
Break-even del business case: +4,81 pp Uplift minimo necessario per coprire i costi ipotizzati.

Il confronto con il break-even è particolarmente importante. Se il costo della campagna è di 98.700 euro e il valore netto incrementale per cliente trattenuto è di 513,33 euro, la campagna deve produrre almeno 4,81 punti percentuali di uplift per risultare economicamente neutrale. L’AME stimato di 5,58 punti percentuali supera questa soglia, ma con un margine relativamente contenuto. La decisione non dovrebbe quindi essere “aumentiamo subito il budget”, bensì: “la campagna appare potenzialmente redditizia, ma dobbiamo misurare meglio l’incertezza dell’effetto prima di scalarla”.

In termini operativi, il risultato suggerisce tre azioni. La prima è non utilizzare il +22,27% come base per il forecast o per il calcolo del ROI. La seconda è stimare intervalli di confidenza, verificare overlap e bilanciamento delle covariate e controllare se l’effetto cambia tra clienti Premium e non Premium. La terza, quando possibile, è progettare la prossima campagna con un gruppo di controllo assegnato casualmente. In questo modo l’azienda potrebbe misurare più direttamente l’incrementalità e ridurre la dipendenza dalle assunzioni necessarie nell’analisi osservazionale.

La conclusione manageriale non è che la campagna abbia fallito. È che il suo valore reale potrebbe essere molto inferiore al valore suggerito dai dati grezzi. Prima di investire di più, bisogna stimare quanto della retention sarebbe avvenuto comunque.

 

Quale decisione dovrebbe prendere il manager?

A questo punto l’analisi non serve soltanto a stimare un effetto. Serve a trasformare i risultati in una decisione proporzionata alla qualità dell’evidenza disponibile.

Il primo dato da non utilizzare come base decisionale è il +22,27% osservato. Questa è la differenza di retention tra clienti trattati e clienti di controllo, ma i due gruppi non erano comparabili in partenza. I clienti raggiunti erano più spesso Premium e avevano caratteristiche di engagement diverse. Utilizzare il +22,27% come incremento causato dall’email significherebbe attribuire alla campagna anche una parte della retention che probabilmente si sarebbe verificata comunque.

Le stime ottenute dopo l’aggiustamento per i confondenti si collocano invece nell’ordine del 5–7%. Questo intervallo è più utile per il management, ma non deve essere interpretato come una certezza: si tratta di stime basate su un modello causale e su assunzioni che devono essere verificate.

1. Estendere la campagna?

Non sulla base del +22,27% osservato.

Un’estensione può essere presa in considerazione se l’effetto incrementale stimato rimane positivo, se il margine economico è sufficiente e se non emergono problemi di overlap, bilanciamento o confondimento non osservato.

La domanda non dovrebbe essere:

“I destinatari hanno avuto una retention maggiore?”

La risposta a questa domanda è già sì.

La domanda utile è:

“Quanta retention aggiuntiva possiamo attribuire alla campagna, rispetto a ciò che sarebbe successo senza l’intervento?”

Se il risultato causale plausibile è nell’ordine di 5–7 punti percentuali, l’eventuale estensione dovrebbe essere graduale e misurabile, non un passaggio immediato a tutti i clienti. Una possibile strategia consiste nell’estendere la campagna a un nuovo gruppo di clienti mantenendo una quota di controllo, così da continuare a misurare l’effetto durante la fase di rollout.

Questa soluzione consente di ridurre il rischio di scalare un’iniziativa sulla base di una sovrastima iniziale e, allo stesso tempo, di raccogliere nuove evidenze in un contesto più vicino a quello operativo.

2. Aumentare il budget?

Nel nostro scenario il punto di pareggio è:

[math]\displaystyle uplift_{BE} = 4{,}81 \text{ punti percentuali}[/math]

Questo significa che la campagna deve generare almeno 4,81 clienti aggiuntivi trattenuti ogni 100 destinatari per coprire i costi ipotizzati.

Uno scenario prudenziale del 5% supera la soglia, ma soltanto di poco. La differenza fra il ritorno positivo e quello negativo è quindi molto sensibile a piccoli cambiamenti nella stima dell’effetto, nel costo della campagna o nel valore economico attribuito a ciascun cliente.

La decisione prudente non sarebbe:

“La campagna è molto redditizia: aumentiamo enormemente il budget.”

Sarebbe invece:

“La campagna sembra potenzialmente redditizia, ma il margine sopra il break-even è ridotto. Raccogliamo evidenza più precisa prima di scalare significativamente l’investimento.”

Dal punto di vista manageriale, questo è un caso in cui la qualità dell’informazione ha un valore economico. Spendere una parte del budget per migliorare la misurazione può essere più conveniente che investire subito molto di più nella campagna.

Forse potrebbe interessarti anche:  I Bias nella Ricerca sui Social Media: Come Riconoscerli e Mitigarli

Un ulteriore aspetto da considerare è il costo marginale. Se l’estensione coinvolge clienti aggiuntivi, non è sufficiente usare il costo medio della prima campagna. Occorre stimare quanto costa raggiungere ogni nuovo cliente e se il valore dell’uplift resta invariato quando si passa da un gruppo selezionato a una popolazione più ampia.

3. Fare un A/B test?

Se possibile, sì.

La difficoltà principale dell’analisi osservazionale nasce dall’assegnazione non casuale dell’email. La prossima campagna dovrebbe quindi essere progettata in modo da rendere la causalità più facile da identificare.

Una parte dei clienti potrebbe essere assegnata casualmente al gruppo trattato e un’altra parte al gruppo di controllo:

Clienti eleggibili
        │
        ├── assegnazione casuale → Email
        │
        └── assegnazione casuale → Controllo

La randomizzazione tende a rendere i due gruppi comparabili anche rispetto a caratteristiche che non abbiamo osservato. In questo modo, la differenza di retention fra trattati e controlli fornisce una misura più diretta dell’incrementalità.

Il gruppo di controllo non dovrebbe essere considerato come una perdita commerciale automatica. È uno strumento di misurazione. Senza gruppo di controllo, l’azienda può inviare più email ma non sapere con sufficiente precisione quante retention aggiuntive abbia generato.

Per un A/B test ben progettato il management dovrebbe definire prima dell’avvio:

  • la metrica primaria, per esempio la retention a 90 giorni;
  • la finestra temporale di osservazione;
  • la dimensione minima dell’effetto economicamente rilevante;
  • la dimensione del campione;
  • eventuali metriche di sicurezza, come disiscrizioni, reclami o peggioramento dell’esperienza cliente;
  • le regole per decidere se interrompere, modificare o estendere la campagna.

In questo modo il test non diventa soltanto un confronto fra percentuali, ma uno strumento di governance della decisione.

4. Migliorare il targeting?

Non necessariamente.

Un segmento con retention elevata non è automaticamente un segmento nel quale l’email funziona meglio. Potrebbe semplicemente essere composto da clienti che sarebbero rimasti attivi anche senza ricevere il messaggio.

Questa distinzione è fondamentale:

Domanda Tipo di analisi
Quali clienti hanno una retention più alta? Analisi descrittiva/predittiva
Quali clienti ricevono più spesso l’email? Analisi del targeting
Su quali clienti l’email produce più effetto? Analisi causale degli effetti eterogenei

Per decidere dove concentrare il budget non basta quindi calcolare l’ATE complessivo. Servono analisi degli heterogeneous treatment effects, cioè degli effetti che possono cambiare fra segmenti, livelli di engagement, anzianità del cliente o rischio di churn.

Il manager dovrebbe chiedersi, per esempio:

“Il segmento Premium presenta un effetto causale maggiore perché l’email funziona meglio su questi clienti, oppure perché questi clienti erano già più fedeli?”

La risposta richiede di confrontare l’effetto dell’intervento all’interno di sottogruppi comparabili, prestando attenzione alla numerosità dei gruppi e al rischio di ottenere risultati casuali cercando troppe differenze.

Un targeting più sofisticato non è sempre un targeting migliore. Se indirizziamo la campagna soltanto ai clienti con alta probabilità di rimanere, potremmo ottenere una retention assoluta elevata ma pochi risultati incrementali. In molti casi il valore maggiore può trovarsi nei clienti a rischio, purché l’intervento abbia su di loro un effetto reale e il costo di attivazione sia sostenibile.

5. Migliorare i dati?

Sì, soprattutto se emergono confondenti importanti non osservati.

Se una variabile influenza sia la probabilità di ricevere l’email sia la retention, ma non è presente nel dataset, nessun algoritmo può controllarla direttamente.

Potrebbe quindi essere necessario:

  • migliorare il CRM;
  • raccogliere variabili pre-campagna più informative;
  • registrare in modo preciso la motivazione dell’assegnazione del trattamento;
  • definire meglio che cosa significa “ricevere la campagna”;
  • distinguere apertura, clic e semplice esposizione al messaggio;
  • tracciare correttamente il gruppo di controllo;
  • collegare il trattamento alla successiva attività del cliente;
  • progettare esperimenti futuri fin dall’inizio.

Questo punto ha una conseguenza manageriale importante: la qualità dell’inferenza causale dipende anche dalla qualità del sistema informativo aziendale. Investire nei dati non significa soltanto migliorare i report. Significa aumentare la qualità delle decisioni future.

Una decisione proporzionata all’evidenza

Possiamo riassumere le decisioni possibili in questo modo:

Decisione Valutazione manageriale
Estendere subito a tutti i clienti Sconsigliato sulla base del solo +22,27% osservato.
Effettuare un’estensione controllata Ragionevole, se mantiene un gruppo di controllo e monitora l’effetto.
Aumentare drasticamente il budget Prematuro, perché 5 pp sono appena sopra il break-even di 4,81 pp.
Progettare un A/B test Raccomandato, se tecnicamente ed eticamente possibile.
Cambiare il targeting Da verificare, non da decidere sulla sola retention descrittiva.
Migliorare CRM e dati pre-campagna Raccomandato, soprattutto in presenza di confondenti non osservati.

La decisione più equilibrata, sulla base di questo esempio, sarebbe quindi una estensione controllata accompagnata da un esperimento randomizzato o da una nuova raccolta dati più rigorosa, non un aumento indiscriminato della spesa.

Conclusione manageriale

L’analisi non dimostra che la campagna sia inutile. Dimostra qualcosa di più utile: il suo valore apparente è molto più grande del valore incrementale che possiamo sostenere dopo aver considerato le differenze fra i clienti.

Il +22,27% osservato deve essere trattato come un indicatore descrittivo. Le stime fra +5 e +7 punti percentuali rappresentano invece una base più plausibile per il ragionamento economico, ma rimangono condizionate alla correttezza del DAG, all’assenza di confondenti rilevanti non misurati e alla presenza di un adeguato overlap.

Nel nostro scenario, un uplift del 5% supera il break-even di soli 0,19 punti percentuali. Per questo la scelta razionale non è massimizzare immediatamente la scala, ma ridurre l’incertezza prima di impegnare nuovo budget.

La sequenza manageriale consigliata è:

[math]\displaystyle \text{analizzare} \rightarrow \text{testare} \rightarrow \text{misurare} \rightarrow \text{scalare}[/math]

Non:

[math]\displaystyle \text{osservare una differenza} \rightarrow \text{attribuirla alla campagna} \rightarrow \text{aumentare il budget}[/math]

La domanda finale non è quindi soltanto se la campagna “funziona”. È se l’effetto incrementale, misurato con sufficiente precisione, supera il costo dell’intervento e rimane positivo quando la campagna viene estesa a nuovi clienti.


Dal “chi ha fatto meglio?” al “cosa ha funzionato?”

Questa è la vera differenza tra analisi descrittiva e inferenza causale.

L’analisi descrittiva ci dice:

“I clienti che hanno ricevuto l’email hanno avuto una retention maggiore.”

L’inferenza causale prova a rispondere:

“Quanto della differenza possiamo attribuire alla campagna?”

E il management ha bisogno soprattutto della seconda risposta.

Perché una decisione di investimento non dovrebbe essere basata su:

“I destinatari hanno fatto meglio.”

Dovrebbe essere basata su:

“Quanto risultato aggiuntivo otteniamo grazie all’intervento, con quale incertezza e a quale costo?”


La lezione finale

La simulazione ci mostra tre numeri molto diversi:

[math]\boxed{22{,}27 \text{ pp}}[/math]

è la differenza osservata.

[math]\boxed{5-7 \text{ pp}}[/math]

è l’ordine di grandezza delle stime causali ottenute dopo l’aggiustamento.

[math]\boxed{6{,}85 \text{ pp}}[/math]

è l’ATE di riferimento della simulazione, calcolato conoscendo il meccanismo generativo dei dati.

La differenza è enorme.

Nel nostro scenario economico, utilizzare erroneamente il 22,27% come uplift incrementale porta a stimare un ritorno netto di circa €358.600.

Utilizzando invece uno scenario prudenziale del 5%, il ritorno scende a circa €3.966.

La conclusione manageriale cambia completamente.

Ma la lezione più importante non è nemmeno questa.

È che l’inferenza causale non consiste nel trovare un algoritmo capace di trasformare automaticamente correlazioni in causalità.

Il processo corretto è:

[math]\displaystyle \boxed{
Processo\ aziendale
\rightarrow
DAG
\rightarrow
Assunzioni
\rightarrow
Identificazione
\rightarrow
Stima
\rightarrow
Diagnostica
\rightarrow
Refutation
\rightarrow
Incertezza
\rightarrow
Valore\ economico
\rightarrow
Decisione
}[/math]

E quando possibile, c’è una strada ancora migliore:

progettare la prossima campagna come un esperimento.

Perché il modo più affidabile per sapere se un intervento funziona non è limitarsi a osservare chi ha ricevuto il trattamento.

È costruire, fin dall’inizio, un confronto credibile con ciò che sarebbe successo senza il trattamento.

Ed è proprio qui che la Data Science smette di essere soltanto analisi dei dati e diventa uno strumento per prendere decisioni migliori.


Riferimenti

  1. DoWhy — Documentazione ufficiale, metodi di stima e propensity score.
  2. Rosenbaum, P. R. & Rubin, D. B. (1983) — The Central Role of the Propensity Score in Observational Studies for Causal Effects. Biometrika.
  3. Hernán, M. A. & Robins, J. M. — Causal Inference: What If.
  4. Kohavi et al. (2012) — Trustworthy Online Controlled Experiments: Five Puzzling Outcomes Explained.

📚Causalità, Uplift Modeling e ROI del marketing

Per capire come passare dalla semplice previsione alla misurazione dell’impatto causale delle campagne, questi articoli approfondiscono Uplift Modeling, CATE, CausalML e le differenze tra correlazione, response modeling e causalità, con esempi pratici in Python:

👉 Tutorial CausalML – Parte 1: dalla teoria all’Uplift Modeling con Python

👉 Uplift Modeling: cos’è e come misurare l’impatto reale del marketing con Python

👉 Cos’è l’Uplift Modeling: come si calcola il CATE e perché è diverso dal Response Modeling

👉 Uplift Modeling con CausalML: guida pratica per massimizzare il ROI delle campagne marketing

👉 Correlazione spuria vs causalità: 10 trappole statistiche, cointegrazione e Uplift Modeling

 

Pubblicità