Evaluando Modelos de Incremento

Evaluación de Modelos de Incremento

CIENCIA DE DATOS CAUSAL

Cómo comparar y seleccionar el mejor modelo uplift

Portada, imagen por el autor.

Una de las aplicaciones más extendidas de la inferencia causal en la industria es el modelo uplift, también conocido como la estimación de los Efectos Promedio Condicionales del Tratamiento.

Cuando estimamos el efecto causal de un tratamiento (un fármaco, un anuncio, un producto, …) en un resultado de interés (una enfermedad, los ingresos de una empresa, la satisfacción del cliente, …), a menudo no solo nos interesa entender si el tratamiento funciona en promedio, sino que nos gustaría saber para qué sujetos (pacientes, usuarios, clientes, …) funciona mejor o peor.

Estimar los efectos incrementales heterogéneos, o uplift, es un paso intermedio esencial para mejorar la orientación de la política de interés. Por ejemplo, es posible que deseemos advertir a ciertas personas que es más probable que experimenten efectos secundarios de un medicamento o mostrar un anuncio solo a un conjunto específico de clientes.

Aunque existen muchos métodos para modelar el uplift, no siempre está claro cuál utilizar en una aplicación específica. Fundamentalmente, debido al problema fundamental de la inferencia causal, el objetivo de interés, el uplift, nunca se observa y, por lo tanto, no podemos validar nuestros estimadores como lo haríamos con un algoritmo de predicción de aprendizaje automático. No podemos apartar un conjunto de validación y seleccionar el modelo de mejor rendimiento, ya que no tenemos una verdad absoluta, ni siquiera en el conjunto de validación, ni siquiera si realizamos un experimento aleatorio.

Entonces, ¿qué podemos hacer? En este artículo, intento cubrir los métodos más populares utilizados para evaluar modelos uplift. Si no estás familiarizado/a con los modelos uplift, te sugiero que primero leas mi artículo introductorio.

Comprendiendo los Meta Aprendices

Editar descripción

towardsdatascience.com

Uplift y Correos Promocionales

Imagina que trabajamos en el departamento de marketing de una empresa de productos interesada en mejorar nuestra campaña de marketing por correo electrónico. Históricamente, enviamos correos electrónicos principalmente a nuevos clientes. Sin embargo, ahora nos gustaría adoptar un enfoque basado en datos y dirigirnos a los clientes para quienes el correo electrónico tiene el mayor impacto positivo en los ingresos. Este impacto también se llama uplift o incrementalidad.

Echemos un vistazo a los datos que tenemos a nuestra disposición. Importo el proceso de generación de datos dgp_promotional_email() de src.dgp. También importo algunas funciones de trazado y bibliotecas de src.utils.

from src.utils import *from src.dgp import dgp_promotional_emaildgp = dgp_promotional_email(n=500)df = dgp.generate_data()df.head()
Instantánea de datos, imagen por el autor

Tenemos información sobre 500 clientes, para quienes observamos si son clientes nuevos, su edad, las ventas que generaron antes de la campaña de correo electrónico (sales_old), si se les envió el correo y las ventas después de la campaña de correo electrónico.

El resultado de interés es ventas, que denotamos con la letra Y. El tratamiento o política que nos gustaría mejorar es la campaña de correo, que denotamos con la letra W. Llamamos a todas las demás variables confundidores o variables de control y las denotamos con X.

Y = 'ventas'W = 'correo'X = ['edad', 'ventas_old', 'nuevos']

El Grafo Acíclico Dirigido (DAG, por sus siglas en inglés) que representa las relaciones causales entre las variables es el siguiente. La relación causal de interés está representada en verde.

Grafo Acíclico Dirigido (DAG) del proceso generador de datos

A partir del DAG, podemos ver que el indicador de cliente new es un confusor y debe ser controlado para identificar el efecto de mail en sales. Por otro lado, age y sales_old no son esenciales para la estimación, pero podrían ser útiles para la identificación. Para obtener más información sobre los DAG y las variables de control, puedes consultar mi artículo introductorio.

DAG y Variables de Control

Editar descripción

towardsdatascience.com

El objetivo del modelado de incremento es recuperar los Efectos Individuales del Tratamiento (ITE) τᵢ, es decir, el efecto incremental en sales de enviar el mail promocional. Podemos expresar el ITE como la diferencia entre dos cantidades hipotéticas: el resultado potencial del cliente si hubiera recibido el correo electrónico, Yᵢ⁽¹⁾, menos el resultado potencial del cliente si no hubiera recibido el correo electrónico, Yᵢ⁽⁰⁾.

Efecto Individual del Tratamiento (ITE), imagen de Autor

Es importante tener en cuenta que, para cada cliente, solo observamos uno de los dos resultados realizados, dependiendo de si realmente recibieron el mail o no. Por lo tanto, el ITE es inherentemente no observable. En cambio, lo que se puede estimar es el Efecto Promedio Condicional del Tratamiento (CATE), es decir, el efecto promedio esperado del tratamiento τᵢ, condicionado a las covariables X. Por ejemplo, el efecto promedio del mail en sales para clientes mayores (age > 50).

Efecto Promedio Condicional del Tratamiento (CATE), imagen de Autor

Para poder recuperar el CATE, necesitamos hacer tres suposiciones.

  1. Desconfundimiento: Y⁽⁰⁾, Y⁽¹⁾ ⊥ W | X
  2. Superposición: 0 < e(X) < 1
  3. Consistencia: Y = W ⋅ Y⁽¹⁾ + (1−W) ⋅ Y⁽⁰⁾

Donde e(X) es el puntaje de propensión, es decir, la probabilidad esperada de ser tratado, condicionada a las covariables X.

Puntaje de propensión, imagen de Autor

En lo que sigue, utilizaremos métodos de aprendizaje automático para estimar el CATE τ(x), los puntajes de propensión e(x) y la función de expectativa condicional (CEF) del resultado, μ(x)

Función de Expectativa Condicional del Resultado (CEF), imagen de Autor

Utilizamos algoritmos de regresión de bosques aleatorios para modelar el CATE y el resultado CEF, mientras que utilizamos la regresión logística para modelar el puntaje de propensión.

from sklearn.ensemble import RandomForestRegressorfrom sklearn.linear_model import LogisticRegressionCVmodel_tau = RandomForestRegressor(max_depth=2)model_y = RandomForestRegressor(max_depth=2)model_e = LogisticRegressionCV()

En este artículo, no ajustamos los modelos subyacentes de aprendizaje automático, pero se recomienda encarecidamente el ajuste fino para mejorar la precisión de los modelos de aumento (por ejemplo, con bibliotecas de auto-ml como FLAML).

Modelos de Aumento

Existen muchos métodos para modelar el aumento o, en otras palabras, para estimar los Efectos Promedio Condicional del Tratamiento (CATE). Dado que el objetivo de este artículo es comparar los métodos para evaluar los modelos de aumento, no explicaremos los métodos en detalle. Para una introducción suave, puedes consultar mi artículo introductorio sobre meta-aprendices.

Los aprendices que consideraremos son los siguientes:

  • Aprendiz S o aprendiz único, introducido por Kunzel, Sekhon, Bickel, Yu (2017)
  • Aprendiz T o aprendiz doble, introducido por Kunzel, Sekhon, Bickel, Yu (2017)
  • Aprendiz X o aprendiz cruzado, introducido por Kunzel, Sekhon, Bickel, Yu (2017)
  • Aprendiz R o aprendiz Robinson, introducido por Nie, Wager (2017)
  • Aprendiz DR o aprendiz doblemente robusto, introducido por Kennedy (2022)

Importamos todos los modelos de la biblioteca econml de Microsoft.

from src.learners_utils import *from econml.metalearners import SLearner, TLearner, XLearnerfrom econml.dml import NonParamDMLfrom econml.dr import DRLearnerS_learner = SLearner(overall_model=model_y)T_learner = TLearner(models=clone(model_y))X_learner = XLearner(models=model_y, propensity_model=model_e, cate_models=model_tau)R_learner = NonParamDML(model_y=model_y, model_t=model_e, model_final=model_tau, discrete_treatment=True)DR_learner = DRLearner(model_regression=model_y, model_propensity=model_e, model_final=model_tau)

Ajustamos los modelos en los datos utilizando fit(), especificando la variable de resultado Y, la variable de tratamiento W y las covariables X.

names = ['SL', 'TL', 'XL', 'RL', 'DRL']learners = [S_learner, T_learner, X_learner, R_learner, DR_learner]for learner in learners:    learner.fit(df[Y], df[W], X=df[X])

¡Ahora estamos listos para evaluar los modelos! ¿Qué modelo debemos elegir?

Funciones de Pérdida del Oráculo

El principal problema de la evaluación de los modelos de aumento es que, incluso con un conjunto de validación y aunque tengamos un experimento aleatorizado o una prueba AB, no observamos nuestra métrica de interés: los Efectos Individuales del Tratamiento. De hecho, solo observamos los resultados realizados, Yᵢ⁽⁰⁾ para los clientes no tratados y Yᵢ⁽¹⁾ para los clientes tratados. Por lo tanto, no podemos calcular el efecto de tratamiento individual, τᵢ = Yᵢ⁽¹⁾ − Yᵢ⁽⁰⁾, en los datos de validación para ningún cliente.

¿Podemos hacer algo para evaluar nuestros estimadores?

La respuesta es sí, pero antes de dar más detalles, primero entendamos qué haríamos si pudiéramos observar los Efectos Individuales del Tratamiento τᵢ.

Pérdida del Oráculo con MSE

Si pudiéramos observar los efectos individuales del tratamiento (pero no lo hacemos, de ahí el atributo “oráculo”), podríamos tratar de medir qué tan lejos están nuestras estimaciones τ̂(Xᵢ) de los valores verdaderos τᵢ. Esto es lo que normalmente hacemos en el aprendizaje automático cuando queremos evaluar un método de predicción: reservamos un conjunto de datos de validación y comparamos los valores predichos y verdaderos en esos datos. Existen muchas funciones de pérdida para evaluar la precisión de la predicción, así que concentrémonos en la más popular: la pérdida de error cuadrático medio (MSE).

Función de pérdida MSE del oráculo, imagen por el autor
def loss_oracle_mse(data, learner):    tau = learner.effect(data[X])    return np.mean((tau - data['effect_on_sales'])**2)

La función compare_methods imprime y muestra las métricas de evaluación calculadas en un conjunto de validación separado.

def compare_methods(learners, names, loss, title=None, subtitle='menor es mejor'):    data = dgp.generate_data(seed_data=1, seed_assignment=1, keep_po=True)    results = pd.DataFrame({        'learner': names,        'pérdida': [loss(data.copy(), learner) for learner in learners]    })    fig, ax = plt.subplots(1, 1, figsize=(6, 4))    sns.barplot(data=results, x="learner", y='pérdida').set(ylabel='')    plt.suptitle(title, y=1.02)    plt.title(subtitle, fontsize=12, fontweight=None, y=0.94)    return resultsresults = compare_methods(learners, names, loss_oracle_mse, title='Pérdida MSE del oráculo')
Valores de pérdida de la función MSE del oráculo, imagen por el autor

En este caso, vemos que el T-learner claramente tiene el peor desempeño, seguido de cerca por el S-learner. Por otro lado, los X-, R- y DR-learners tienen un desempeño significativamente mejor, siendo el DR-learner el ganador de la carrera.

Sin embargo, esta podría no ser la mejor función de pérdida para evaluar nuestro modelo de uplift. De hecho, el modelado de uplift es solo un paso intermedio hacia nuestro objetivo final: mejorar los ingresos.

Ganancia de Política del Oráculo

Dado que nuestro objetivo final es mejorar los ingresos, podríamos evaluar los estimadores según cuánto aumenten los ingresos, dada una cierta función de política. Supongamos, por ejemplo, que tenemos un costo de 0.01$ por enviar un correo electrónico. Entonces, nuestra política sería tratar a cada cliente con un efecto promedio del tratamiento condicional predicho por encima de 0.01$.

costo = 0.01

¿Cuánto aumentarían realmente nuestros ingresos? Definamos con d(τ̂) nuestra función de política, tal que d=1 si τ ≥ 0.1 y d=0 en caso contrario. Entonces, nuestra función de ganancia (mayor es mejor) es:

Función de ganancia de política del oráculo, imagen por el autor

Nuevamente, esta es una función de pérdida “oráculo” que no se puede calcular en realidad, ya que no observamos los efectos individuales del tratamiento.

def gain_oracle_policy(data, learner):    tau_hat = learner.effect(data[X])    return np.sum((data['effect_on_sales'] - costo) * (tau_hat > costo))results = compare_methods(learners, names, gain_oracle_policy, title='Ganancia de Política del Oráculo', subtitle='mayor es mejor')
Valores de ganancia de política del oráculo, imagen por el autor

En este caso, el S-learner es claramente el peor intérprete, sin efecto en los ingresos. El T-learner lleva a ganancias modestas, mientras que los X-, R- y DR-learners llevan a ganancias agregadas, siendo el X-learner ligeramente superior.

Funciones de Pérdida Prácticas

En la sección anterior, hemos visto dos ejemplos de funciones de pérdida que nos gustaría calcular si pudiéramos observar los Efectos Individuales del Tratamiento τᵢ. Sin embargo, en la práctica, incluso con un experimento aleatorizado e incluso con un conjunto de validación, no observamos el ITE, nuestro objeto de interés. Ahora cubriremos algunas medidas que intentan evaluar los modelos de uplift, dados esta restricción práctica.

Pérdida de resultado

El primer enfoque más simple es cambiar a una variable de pérdida diferente. Si bien no podemos observar los efectos de tratamiento individual, τᵢ, aún podemos observar nuestro resultado Yᵢ. Esto no es exactamente nuestro objeto de interés, pero podríamos esperar que un modelo de aumento que funcione bien en términos de predecir y también produzca buenas estimaciones de τ.

Una función de pérdida de este tipo podría ser la pérdida de MSE de resultado, que es la función de pérdida de MSE habitual para los métodos de predicción.

Función de pérdida de MSE de resultado, imagen de Autor

El problema aquí es que no todos los modelos producen directamente una estimación de μ(x). Por lo tanto, omitimos esta comparación y recurrimos a métodos que pueden evaluar cualquier modelo de aumento.

Pérdida de predicción a predicción

Otro enfoque muy simple podría ser comparar las predicciones del modelo entrenado en el conjunto de entrenamiento con las predicciones de otro modelo entrenado en el conjunto de validación. Aunque intuitivo, este enfoque podría ser extremadamente engañoso.

def loss_pred(data, learner):    tau = learner.effect(data[X])    learner2 = copy.deepcopy(learner).fit(data[Y], data[W], X=data[X])    tau2 = learner2.effect(data[X])    return np.mean((tau - tau2)**2)results = compare_methods(learners, names, loss_pred, 'Pérdida de predicción a predicción')
Valores de pérdida de MSE de predicción a predicción, imagen de Autor

No sorprendentemente, esta métrica funciona extremadamente mal y no debería usarse nunca, ya que premia a los modelos que son consistentes, independientemente de su calidad. Un modelo que siempre predice una constante CATE aleatoria para cada observación obtendría una puntuación perfecta.

Pérdida de distribución

Un enfoque diferente es preguntar: ¿qué tan bien podemos igualar la distribución de los resultados potenciales? Podemos hacer este ejercicio tanto para los resultados potenciales tratados como para los no tratados. Tomemos el último caso. Supongamos que tomamos las ventas observadas para los clientes que no recibieron el mail y las ventas observadas menos el CATE estimado τ̂(x) para los clientes que sí recibieron el mail. Según la suposición de no confusión, estas dos distribuciones del resultado potencial no tratado deberían ser similares, condicionales a las covariables X.

Por lo tanto, esperamos que la distancia entre las dos distribuciones sea cercana si hemos estimado correctamente los efectos del tratamiento.

Distancia del resultado potencial no tratado, imagen de Autor

También podemos hacer el mismo ejercicio para el resultado potencial tratado.

Distancia del resultado potencial tratado, imagen de Autor

Usamos la distancia de energía como métrica de distancia.

from dcor import energy_distancedef loss_dist(data, learner):    tau = learner.effect(data[X])    data.loc[data.mail==1, 'sales'] -= tau[data.mail==1]    return energy_distance(data.loc[data.mail==0, [Y] + X], data.loc[data.mail==1, [Y] + X], exponent=2)results = compare_methods(learners, names, loss_dist, 'Pérdida de distribución')
Valores de distancia del resultado potencial no tratado, imagen de Autor

Esta medida es extremadamente ruidosa y recompensa al S-learner seguido por el T-learner, que en realidad son los dos modelos con peor rendimiento.

Diferencia arriba-abajo de la mediana

La pérdida arriba-abajo de la mediana trata de responder a la pregunta: ¿nuestro modelo de incremento está detectando alguna heterogeneidad? En particular, si tomamos el conjunto de validación y dividimos la muestra en por encima de la mediana y por debajo de la mediana de incremento predicho τ̂(x), ¿qué tan grande es la diferencia real en el efecto promedio, estimado con un estimador de diferencia de medias? Esperaríamos que los estimadores mejores dividieran mejor la muestra en efectos altos y efectos bajos.

from statsmodels.formula.api import ols def loss_ab(data, learner):    tau = learner.effect(data[X]) + np.random.normal(0, 1e-8, len(data))    data['above_median'] = tau >= np.median(tau)    param = ols('sales ~ mail * above_median', data=data).fit().params[-1]    return paramresults = compare_methods(learners, names, loss_ab, title='Diferencia arriba-abajo de la mediana', subtitle='mayor es mejor')
Valores incrementales de la diferencia arriba-abajo de la mediana, imagen de Author

Desafortunadamente, la diferencia arriba-abajo de la mediana premia al T-learner, que está entre los modelos con peor rendimiento.

Es importante tener en cuenta que los estimadores de diferencia de medias en los dos grupos (por encima y por debajo de la mediana τ̂(x)) no están garantizados de ser imparciales, incluso si los datos provienen de un experimento aleatorio. De hecho, hemos dividido los dos grupos en una variable, τ̂(x), que es altamente endógena. Por lo tanto, el método debe usarse con precaución.

Curva de Incremento

Una extensión de la prueba arriba-abajo de la mediana es la curva de incremento. La idea es simple: en lugar de dividir la muestra en dos grupos basados en la mediana (cuantil 0.5), ¿por qué no dividir los datos en más grupos (más cuantiles)?

Para cada grupo, calculamos la estimación de diferencia de medias y trazamos su suma acumulativa en función del cuantil correspondiente. El resultado se llama la curva de incremento. La interpretación es simple: cuanto mayor sea la curva, mejor seremos capaces de separar observaciones de alto y bajo efecto. Sin embargo, también se aplica el mismo aviso: las estimaciones de diferencia de medias no son imparciales. Por lo tanto, deben usarse con precaución.

def generate_uplift_curve(df):    Q = 20    df_q = pd.DataFrame()    data = dgp.generate_data(seed_data=1, seed_assignment=1, keep_po=True)    ate = np.mean(data[Y][data[W]==1]) - np.mean(data[Y][data[W]==0])    for learner, name in zip(learners, names):        data['tau_hat'] = learner.effect(data[X])        data['q'] = pd.qcut(-data.tau_hat + np.random.normal(0, 1e-8, len(data)), q=Q, labels=False)        for q in range(Q):            temp = data[data.q <= q]            uplift = (np.mean(temp[Y][temp[W]==1]) - np.mean(temp[Y][temp[W]==0])) * q / (Q-1)            df_q = pd.concat([df_q, pd.DataFrame({'q': [q], 'uplift': [uplift], 'learner': [name]})], ignore_index=True)        fig, ax = plt.subplots(1, 1, figsize=(8, 5))    sns.lineplot(x=range(Q), y=ate*range(Q)/(Q-1), color='k', ls='--', lw=3)    sns.lineplot(x='q', y='uplift', hue='learner', data=df_q);    plt.suptitle('Curva de Incremento', y=1.02, fontsize=28, fontweight='bold')    plt.title('mayor es mejor', fontsize=14, fontweight=None, y=0.96)generate_uplift_curve(df)
Curva de aumento, imagen por el autor

Aunque probablemente no sea el mejor método para evaluar modelos de aumento, la curva de aumento es muy importante para comprender e implementar estos modelos. De hecho, para cada modelo, nos indica cuál es el efecto promedio esperado del tratamiento (eje y) a medida que aumentamos la proporción de la población tratada (eje x).

Correspondencia con el vecino más cercano

Los últimos métodos que analizamos utilizaron datos agregados para entender si los métodos funcionan en grupos más grandes. En cambio, la correspondencia con el vecino más cercano intenta comprender qué tan bien un modelo de aumento predice los efectos individuales del tratamiento. Sin embargo, dado que los EIT no son observables, intenta construir un proxy emparejando observaciones tratadas y de control en características observables X.

Por ejemplo, si tomamos todas las observaciones tratadas (i: Wᵢ=1) y encontramos el vecino más cercano en el grupo de control (NN₀(Xᵢ)), la función de pérdida de MSE correspondiente es

Función de pérdida del vecino más cercano, imagen por el autor
from scipy.spatial import KDTreedef loss_nn(data, learner):    tau_hat = learner.effect(data[X])    nn0 = KDTree(data.loc[data[W]==0, X].values)    control_index = nn0.query(data.loc[data[W]==1, X], k=1)[-1]    tau_nn = data.loc[data[W]==1, Y].values - data.iloc[control_index, :][Y].values    return np.mean((tau_hat[data[W]==1] - tau_nn)**2)results = compare_methods(learners, names, loss_nn, title='Pérdida del vecino más cercano')
Valores de pérdida del vecino más cercano, imagen por el autor

En este caso, la pérdida del vecino más cercano funciona bastante bien, identificando los dos métodos de peor rendimiento, el S-learner y el T-learner.

Pérdida de IPW

La función de pérdida de Peso Inverso de Probabilidad (IPW) fue propuesta por Gutierrez, Gerardy (2017), y es la primera de tres métricas que vamos a ver que utilizan un pseudo-resultado Y* para evaluar el estimador. Los pseudo-resultados son variables cuyo valor esperado es el Efecto Promedio del Tratamiento Condicional, pero que son demasiado volátiles para ser utilizados directamente como estimaciones. Para una explicación más detallada de los pseudo-resultados, sugiero mi artículo sobre los árboles de regresión causal. El pseudo-resultado correspondiente a la pérdida de IPW es

Pseudo-resultado de IPW, imagen por el autor

por lo que la función de pérdida correspondiente es

Función de pérdida de IPW, imagen por el autor
def loss_ipw(data, learner):    tau_hat = learner.effect(data[X])    e_hat = clone(model_e).fit(data[X], data[W]).predict_proba(data[X])[:,1]    tau_gg = data[Y] * (data[W] - e_hat) / (e_hat * (1 - e_hat))    return np.mean((tau_hat - tau_gg)**2)results = compare_methods(learners, names, loss_ipw, title='Pérdida de IPW')
Valores de la función de pérdida IPW, imagen de Autor

La función de pérdida IPW es extremadamente ruidosa. Una solución es utilizar sus variaciones más robustas, la R-pérdida o la DR-pérdida que presentamos a continuación.

R Pérdida

La R-pérdida fue introducida junto con el R-learner por Nie, Wager (2017), y es esencialmente la función objetivo del R-learner. Al igual que con la pérdida IPW, la idea es tratar de igualar un resultado pseudo cuyo valor esperado es el Efecto Promedio Condicional del Tratamiento.

Pseudo resultado R, imagen de Autor

La función de pérdida correspondiente es

Función de pérdida R, imagen de Autor
def loss_r(data, learner):    tau_hat = learner.effect(data[X])    y_hat = clone(model_y).fit(df[X + [W]], df[Y]).predict(data[X + [W]])    e_hat = clone(model_e).fit(df[X], df[W]).predict_proba(data[X])[:,1]    tau_nw = (data[Y] - y_hat) / (data[W] - e_hat)    return np.mean((tau_hat - tau_nw)**2)compare_methods(learners, names, loss_r, title='R Pérdida')
Valores de la pérdida R, imagen de Autor

La R-pérdida es sensiblemente menos ruidosa que la pérdida IPW y claramente aísla al S-learner. Sin embargo, tiende a favorecer a su correspondiente learner, el R-learner.

DR Pérdida

La DR-pérdida es la función objetivo del DR-learner, y fue introducida por primera vez por Saito, Yasui (2020). Al igual que con la pérdida IPW y la pérdida R, la idea es tratar de igualar un resultado pseudo, cuyo valor esperado es el Efecto Promedio Condicional del Tratamiento. El pseudo resultado DR está fuertemente relacionado con el estimador AIPW, también conocido como estimador doblemente robusto, de ahí el nombre DR.

Pseudo resultado DR, imagen de Autor

La función de pérdida correspondiente es

Función de pérdida DR, imagen de Autor
def loss_dr(data, learner):    tau_hat = learner.effect(data[X])    y_hat = clone(model_y).fit(df[X + [W]], df[Y]).predict(data[X + [W]])    mu1 = clone(model_y).fit(df[X + [W]], df[Y]).predict(data[X + [W]].assign(mail=1))    mu0 = clone(model_y).fit(df[X + [W]], df[Y]).predict(data[X + [W]].assign(mail=0))    e_hat = clone(model_e).fit(df[X], df[W]).predict_proba(data[X])[:,1]    tau_nw = mu1 - mu0 + (data[Y] - y_hat) * (data[W] - e_hat) / (e_hat * (1 - e_hat))    return np.mean((tau_hat - tau_nw)**2)results = compare_methods(learners, names, loss_dr, title='DR Pérdida')
Valores de pérdida de DR, imagen por el autor

En cuanto a la pérdida R, la pérdida DR tiende a favorecer a su respectivo aprendiz, el aprendiz DR. Sin embargo, proporciona una clasificación más precisa en términos de la exactitud de los algoritmos.

Ganancia de Política Empírica

La última función de pérdida que vamos a analizar es diferente a todas las demás que hemos visto hasta ahora, ya que no se centra en qué tan bien podemos estimar los efectos del tratamiento, sino en qué tan bien se desempeñaría la política de tratamiento óptima correspondiente. En particular, Hitsch, Misra, Zhang (2023) proponen la siguiente función de ganancia:

Función de ganancia de política empírica, imagen por el autor

donde c es el costo del tratamiento y d es la política de tratamiento óptima dada la CATE estimada τ̂(Xᵢ). En nuestro caso, asumimos un costo de tratamiento individual de c=0.01$, por lo que la política óptima es tratar a cada cliente con una CATE estimada mayor que 0.01.

Los términos Wᵢ⋅d(τ̂) y (1-Wᵢ)⋅(1-d(τ̂)) implican que utilizamos para el cálculo solo a los individuos para los cuales el tratamiento real W corresponde al óptimo, d.

def gain_policy(data, learner):    tau_hat = learner.effect(data[X])    e_hat = clone(model_e).fit(data[X], data[W]).predict_proba(data[X])[:,1]    d = tau_hat > cost    return np.sum((d * data[W] * (data[Y] - cost)/ e_hat + (1-d) * (1-data[W]) * data[Y] / (1-e_hat)))results = compare_methods(learners, names, gain_policy, title='Ganancia de Política Empírica', subtitle='mayor es mejor')
Valores de ganancia de política empírica, imagen por el autor

La ganancia de política empírica funciona muy bien, aislando los dos métodos de peor rendimiento, los aprendices S y T.

Metaestudios

En este artículo, hemos presentado una amplia variedad de métodos para evaluar modelos de mejora, también conocidos como estimadores del efecto promedio condicional del tratamiento. También los hemos probado en nuestro conjunto de datos simulado, que es un ejemplo muy especial y limitado. ¿Cómo se desempeñan estas métricas en general?

Schuler, Baiocchi, Tibshirani, Shah (2018) compara la pérdida S, la pérdida T, la pérdida R, en datos simulados, para los estimadores correspondientes. Encuentran que la pérdida R “es la métrica del conjunto de validación que, cuando se optimiza, conduce de manera más consistente a la selección de un modelo de alto rendimiento”. Los autores también detectan el llamado sesgo de congenialidad: las métricas como la pérdida R o DR tienden a estar sesgadas hacia el aprendiz correspondiente.

Curth, van der Schaar (2023) estudia una amplia gama de aprendices desde una perspectiva teórica. Encuentran que “no existe un criterio de selección existente que sea el mejor en todas las condiciones experimentales que consideramos”.

Mahajan, Mitliagkas, Neal, Syrgkanis (2023) es el estudio más completo en términos de alcance. Los autores comparan muchas métricas en 144 conjuntos de datos y 415 estimadores. Encuentran que “ninguna métrica domina significativamente al resto”, pero “las métricas que utilizan elementos DR parecen estar siempre entre los candidatos ganadores”.

Conclusión

En este artículo, hemos explorado múltiples métodos para evaluar modelos de mejora. El principal desafío es la falta de observabilidad de la variable de interés, los Efectos Individuales del Tratamiento. Por lo tanto, los diferentes métodos tratan de evaluar modelos de mejora utilizando otras variables, utilizando resultados proxy o aproximando el efecto de las políticas óptimas implícitas.

Es difícil recomendar el uso de un solo método ya que no hay consenso sobre cuál es el que funciona mejor, ni desde un punto de vista teórico ni empírico. Las funciones de pérdida que utilizan elementos R- y DR- tienden a tener un rendimiento consistentemente mejor, pero también están sesgadas hacia los correspondientes aprendices. Sin embargo, comprender cómo funcionan estas métricas puede ayudar a comprender sus sesgos y limitaciones para tomar las decisiones más apropiadas en función del escenario específico.

Referencias

  • Curth, van der Schaar (2023), “En busca de ideas, no balas mágicas: hacia la desmitificación del dilema de selección del modelo en la estimación del efecto de tratamiento heterogéneo”
  • Gutierrez, Gerardy (2017), “Inferencia causal y modelado de elevación: una revisión de la literatura”
  • Hitsch, Misra, Zhang (2023), “Efectos de tratamiento heterogéneos y evaluación de la política de orientación óptima”
  • Kennedy (2022), “Hacia una estimación óptima de efectos causales heterogéneos con doble robustez”
  • Kunzel, Sekhon, Bickel, Yu (2017), “Meta-aprendices para la estimación de efectos de tratamiento heterogéneos utilizando aprendizaje automático”
  • Mahajan, Mitliagkas, Neal, Syrgkanis (2023), “Análisis empírico de la selección de modelos para la estimación de efectos causales heterogéneos”
  • Nie, Wager (2017), “Estimación cuasi-oráculo de efectos de tratamiento heterogéneos”
  • Saito, Yasui (2020), “Validación cruzada contrafactual: procedimiento de selección de modelos estables para modelos de inferencia causal”
  • Schuler, Baiocchi, Tibshirani, Shah (2018), “Una comparación de métodos para la selección de modelos al estimar efectos de tratamiento individuales”
  • Comprendiendo los Meta Aprendices
  • Comprendiendo AIPW, el Estimador Doblemente Robusto
  • Comprendiendo los Árboles Causales
  • De los Árboles Causales a los Bosques

Código

Puedes encontrar el Jupyter Notebook original aquí:

Blog-Posts/notebooks/evaluate_uplift.ipynb en main · matteocourthoud/Blog-Posts

Código y cuadernos para mis publicaciones en VoAGI. Contribuye al desarrollo de matteocourthoud/Blog-Posts creando un…

github.com

¡Gracias por leer!

¡Realmente lo aprecio! 🤗 Si te gustó la publicación y quieres ver más, considera seguirme. Publico una vez a la semana sobre temas relacionados con la inferencia causal y el análisis de datos. Intento mantener mis publicaciones simples pero precisas, siempre proporcionando código, ejemplos y simulaciones.

También, un pequeño descargo de responsabilidad: Escribo para aprender, por lo que los errores son normales, aunque hago todo lo posible por evitarlos. Por favor, cuando los encuentres, házmelo saber. ¡También aprecio las sugerencias sobre nuevos temas!