Optimización del presupuesto en campañas de marketing con analítica predictiva y prescriptiva

Optimización del presupuesto en campañas de marketing con analítica predictiva y prescriptiva

Francisco Espiga
Abril, 2021

Más sobre ciencia de datos: cienciadedatos.net

Introducción


En este artículo exploraremos cómo el uso de modelos predictivos y prescriptivos nos permiten mejorar la intención de compra de los clientes detectando los factores (drivers) más influyentes en su decisión y optimizando el reparto del presupuesto (budget) para actividades de mejora de percepción del cliente.

Tras el análisis descriptivo inicial, utilizaremos un modelo de regresión logística para la etapa predictiva y optimización lineal para la prescriptiva.

Información de sesión


In [1]:
# Librerías
# ==============================================================================
from sinfo import sinfo
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt 
import random
import shap
import random 
import pyomo.environ as pyo

from sklearn.linear_model import LogisticRegression 
from sklearn.metrics import confusion_matrix, classification_report
from sklearn.model_selection import train_test_split
random.seed(1211)

sinfo()
-----
matplotlib  3.2.2
numpy       1.19.5
pandas      1.0.5
pyomo       5.7.1
shap        0.37.0
sinfo       0.3.1
sklearn     0.22.1
-----
IPython             7.12.0
jupyter_client      6.1.5
jupyter_core        4.6.3
jupyterlab          1.2.6
notebook            6.0.3
-----
Python 3.7.6 (default, Jan  8 2020, 19:59:22) [GCC 7.3.0]
Linux-5.4.0-70-generic-x86_64-with-debian-buster-sid
8 logical CPU cores, x86_64
-----
Session information updated at 2021-03-29 14:22

Contexto de negocio


Para maximizar el rendimiento de las campañas de marketing, es muy importante ser capaz de valorar qué características de nuestros productos son las que más valoran nuestros clientes. Disponer de esta información permite dirigir las futuras inversiones y esfuerzos.

Uno de los instrumentos para conectar con los clientes potenciales son las encuestas, cada vez más sencillas de llevar a cabo y con un alcance mayor en el nuevo paradigma digital que estamos viviendo.

A lo largo de este documento, veremos cómo utilizar las respuestas de los entrevistados para identificar qué factores determinan su intención de compra y cuantificar su importancia relativa. Una vez obtenida esa importancia, es importante optimizar la asignación del presupuesto a cada factor (palanca) de modo que, la mejora de la percepción del cliente, se traduzca en el mayor incremento posible de intención de compra global.

Para contextualizarlo, supondremos que trabajamos en el sector de la automoción y queremos averiguar de cara al lanzamiento de un nuevo vehículo qué características son las que influyen más en nuestros clientes.

Caso de uso


Se ha planteado a distintas personas que han entrado en nuestra web una pequeña encuesta, pidiéndoles que cifren de 0 a 10 cuánto valoran en los productos de nuestra marca las siguientes características:

  • Diseño y estética

  • Consumo de combustible

  • Fiabilidad de la mecánica

  • Innovación

  • Precio

Además, se les ha preguntado por su intención de compra en los próximos 6 meses con valores en el mismo rango.

Tras haber obtenido un número razonable de encuestas (~10000), tenemos un set de datos con el siguiente aspecto:

In [2]:
pd.DataFrame.from_dict(
    dict(zip(['diseño', 'consumo', 'fiabilidad', 'innovación', 'precio', 'intención_compra'],
             [np.random.randint(0,10,5) for i in range(6)])
        )
)
Out[2]:
diseño consumo fiabilidad innovación precio intención_compra
0 2 2 1 0 7 7
1 5 5 9 9 5 9
2 6 5 2 3 2 3
3 9 8 7 2 1 2
4 9 9 0 2 0 2

Escalaremos los distintos drivers entre 0 y 1 (dividiendo por 10) y consideraremos únicamente como compras potenciales aquellas con una probabilidad de intención superior al 95%.

Vamos a suponer que nuestros clientes le dan una importancia base de:

  • 1 a la innovación y al diseño.

  • 2 al consumo, a la interacción de precio y fiabilidad.

  • 3 al precio, que además está relacionado cuadráticamente con la intención de compra.

Teniendo en cuenta esto, su utilidad vendrá dada por la expresión:

$$z=Innovacion+Diseño+2*Consumo+2*(Precio\times Fiabilidad) + 3*(Precio²)$$
In [3]:
n_samples = 10000

# variables explicativas -------------------------------------------------------
diseño = np.random.randint(0,10,n_samples)/10
consumo = np.random.randint(0,10,n_samples)/10
fiabilidad = np.random.randint(0,10,n_samples)/10
innovacion = np.random.randint(0,10,n_samples)/10
precio = np.random.randint(0,10,n_samples)/10
X = np.array([diseño, consumo, fiabilidad, innovacion, precio]).transpose()
feature_labels = ['diseño', 'consumo', 'fiabilidad', 'innovacion', 'precio']

# respuesta --------------------------------------------------------------------
z = (innovacion + diseño + 2*consumo + 2*precio*fiabilidad +3*((precio)**2))
pi_x = np.exp(z)/(1+np.exp(z))
y = 1*(pi_x>0.95)
In [4]:
pd.Series(pi_x).hist();

Modelado


A continuación, exploraremos diferentes opciones de modelado y cómo extraer insights de ellas. En este caso, lo formularemos como un problema de clasificación y nuestra respuesta será binaria:

  • 1: fuerte intención de compra.

  • 0: sin intención de compra.

Para no llegar a conclusiones equivocadas y en caso de tratar con datos reales, sería importante verificar que la variable respuesta del el dataset esté balanceada. Podemos comprobar que es así y cada clase tiene aproximadamente un 50% de los datos. En caso contrario, podríamos utilizar diversas estrategias, como subsampling de la clase dominante o bien hacer oversampling de la minoritaria.

El subsampling es menos deseable, ya que perdemos información y no tenemos la garantía de que la muestra de datos que extraemos sea representativo del resto. Por otro lado, hacer oversampling de la clase minoritaria, recurriendo por ejemplo a SMOTE o utilizar k-fold cross validation, de modo que en cada subset de los datos de entrenamiento tomemos la clase minoritaria y un número de muestras equivalente de la dominante nos permite utilizar todos los datos de que disponemos.

In [5]:
pd.Series(y).hist()
Out[5]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f9034da2710>
In [6]:
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size = 0.8, stratify = y)

Regresión logística


Aunque en este caso sabemos que la regresión logística no va a ser suficiente para modelar de manera totalmente precisa nuestro problema, debido a las relaciones cuadráticas con el precio y la interacción precio-fiabilidad, es interesante utilizarla como baseline frente a la que comparar el resto de modelos, al ser sencilla de implementar y explicable.

In [7]:
clf = LogisticRegression(random_state=0).fit(X_train, y_train)

Evaluamos la calidad del modelo utilizando la matriz de confusión y observamos que tanto para train como para test, los resultados son homogéneos y de una calidad aceptable. En este caso, somos capaces de determinar con una precisión (accuracy) superior al 95% si un cliente va a comprar o no.

In [8]:
confusion_matrix(y_train, clf.predict(X_train), normalize='true')
Out[8]:
array([[0.96797241, 0.03202759],
       [0.03273281, 0.96726719]])
In [9]:
print(classification_report(y_train, clf.predict(X_train)))
              precision    recall  f1-score   support

           0       0.97      0.97      0.97      4059
           1       0.97      0.97      0.97      3941

    accuracy                           0.97      8000
   macro avg       0.97      0.97      0.97      8000
weighted avg       0.97      0.97      0.97      8000

In [10]:
CM_test = confusion_matrix(y_test, clf.predict(X_test), normalize='true')
In [11]:
print(classification_report(y_test, clf.predict(X_test)))
              precision    recall  f1-score   support

           0       0.97      0.96      0.97      1015
           1       0.96      0.97      0.97       985

    accuracy                           0.97      2000
   macro avg       0.97      0.97      0.97      2000
weighted avg       0.97      0.97      0.97      2000

Importancia de los drivers de compra


A continuación, vamos a utilizar los shap values para determinar, tanto la importancia relativa de las distintas variables exógenas (nuestros drivers de compra), como para cuantificar el impacto (utilidad marginal) que tiene cada driver sobre la percepción. Para esto último se recurre a gráficos de dependencias parciales (PDP).

In [12]:
df_test = pd.DataFrame(X_test, columns = feature_labels)
In [13]:
explainer = shap.LinearExplainer(clf, X_train, feature_perturbation="interventional")
shap_values = explainer.shap_values(df_test)
The feature_perturbation option is now deprecated in favor of using the appropriate masker (maskers.Independent, or maskers.Impute)
In [14]:
shap.summary_plot(shap_values, df_test, plot_type='bar')

En este caso, vemos que el modelo es capaz de captar la importancia relativa de los distintos drivers de compra, aunque la interacción de fiabilidad y precio se ve enmascarada por la importancia de éste.

Esto es muy interesante pero insuficiente a la hora de determinar el impacto positivo de acciones de marketing específicas para cada driver, para ello y en el caso concreto de la regresión logística, tendremos que extraer los coeficientes del modelo para conectar cómo la variación de la percepción de cada driver afectaría a la intención de compra.

Usando los gráficos de dependencia parcial, podemos ganar una intuición de cómo cada driver afectaría a la intención antes de pasar a modelar el problema de optimización del presupuesto.

In [15]:
shap.partial_dependence_plot("precio", clf.predict, df_test,
                             model_expected_value=True, feature_expected_value=True)
In [16]:
shap.partial_dependence_plot("consumo", clf.predict, df_test,
                             model_expected_value=True, feature_expected_value=True)
In [17]:
shap.partial_dependence_plot("diseño", clf.predict, df_test,
                             model_expected_value=True, feature_expected_value=True)
In [18]:
shap.partial_dependence_plot("fiabilidad", clf.predict, df_test,
                             model_expected_value=True, feature_expected_value=True)
In [19]:
shap.partial_dependence_plot("innovacion", clf.predict, df_test,
                             model_expected_value=True, feature_expected_value=True)

Observamos cómo los drivers principales son efectivamente el precio y el consumo.

Si bien una mejora en la percepción de cualquier driver conlleva un aumento de la intención de compra, la innovación, diseño y fiabilidad tienen una contribución marginal mucho menor que los otros dos, que serán en los que nos interesará centrarnos en primer término.

In [20]:
dict(zip(feature_labels, np.log(clf.coef_).reshape(-1)))
Out[20]:
{'diseño': 1.656303159853731,
 'consumo': 2.3224237883119336,
 'fiabilidad': 1.4763473464469679,
 'innovacion': 1.7322586304038865,
 'precio': 2.922333540338283}

Por último, podemos utilizar shap para analizar la decisión de compra de cada individuo de la muestra.

In [21]:
shap.initjs()
In [22]:
random_ok = np.random.choice(np.where(y_test == 1)[0].reshape(-1), 1)[0]
random_ko = np.random.choice(np.where(y_test == 0)[0].reshape(-1), 1)[0]
random_ok, random_ko
Out[22]:
(460, 383)
In [23]:
shap.force_plot(
    explainer.expected_value, shap_values[random_ok,:], X_test[random_ok,:],
    feature_names=feature_labels
)
Out[23]:
Visualization omitted, Javascript library not loaded!
Have you run `initjs()` in this notebook? If this notebook was from another user you must also trust this notebook (File -> Trust notebook). If you are viewing this notebook on github the Javascript has been stripped for security. If you are using JupyterLab this error is because a JupyterLab extension has not yet been written.
In [24]:
shap.force_plot(
    explainer.expected_value, shap_values[random_ko,:], X_test[random_ko,:],
    feature_names=feature_labels
)
Out[24]:
Visualization omitted, Javascript library not loaded!
Have you run `initjs()` in this notebook? If this notebook was from another user you must also trust this notebook (File -> Trust notebook). If you are viewing this notebook on github the Javascript has been stripped for security. If you are using JupyterLab this error is because a JupyterLab extension has not yet been written.

La interpretación que haríamos es que el primer cliente, que se plantea la adquisición en los próximos 6 meses, actúa movido principalmente por el precio pero también con una contribución equivalente a su decisión de los drivers de diseño y fiabilidad.

Por otro lado, el cliente que lo ha descartado, a pesar de tener una buena percepción de nuestro producto a nivel consumo, la del driver principal, el precio, así como la de la fiabilidad son tan bajas que desplazan la decisión a descartar la compra.

In [25]:
plt.scatter(np.sum(shap_values, axis = 1), y_test);

Optimización del presupuesto (budget)


Vamos a suponer ahora que queremos mejorar la percepción del cliente de cada uno de los drivers y para ello disponemos de un presupuesto de 1000 unidades monetarias (u.m.).

Cada mejora porcentual en la percepción de los drivers tendrá un coste asociado y un impacto en la intención de compra, que es lo que buscamos maximizar. Utilizaremos los datos de las encuestas y el modelo de regresión logística que hemos calculado previamente para construir el modelo de optimización.

Posteriormente, con los datos de validación, mediremos el impacto de nuestra asignación con la nueva intención de compra. Es importante tener en cuenta que, es gracias a tener una precisión adecuada en nuestro modelo predictivo (la regresión logística), es decir, el modelo capturar de manera bastante acertada la relación entre drivers e intención de compra, lo que nos permite pasar a la siguiente etapa, la prescriptiva. De no ser así, deberíamos buscar un modelo mejor ya que, si no, cualquier optimización posterior estaría basada en unas premisas que no son reflejo de la realidad del negocio.

Utilizamos los datos de las encuestas para saber el punto de partida y el margen de mejora:

In [26]:
np.mean(X, axis = 0)
Out[26]:
array([0.44847, 0.4505 , 0.4463 , 0.45117, 0.45125])
In [27]:
X_train.shape
Out[27]:
(8000, 5)

Todos los drivers tienen una percepción de en torno al 45%, consideraremos que el máximo margen de mejora por tanto sería del 50%, llevando la percepción de cada driver hasta un teórico máximo del 95%.

Formalización del problema de optimización


A la hora de diseñar la función objetivo, tenemos que pensar que nuestra meta global es, mediante las acciones de marketing correspondientes, aumentar las ventas totales y ello se reflearía en el número de encuestados que habrían contestado afirmativamente a la intención de compra. Es decir :

$$ max\;z= \sum_{i\in sEncuestados}\pi(x)=\;\frac{1}{1+e^{-\beta_0 + \sum \beta_j x_j}} $$

Como hemos considerado que la intención de compra es una variable modelada como una distribución de Bernouilli y llamando $p$ a la probabilidad $P(Y=1)$, tenemos que:

$$ l=\frac{p}{1-p}=\beta_0 + \sum \beta_j x_j $$

Al ser las intenciones de compra de cada encuestado sucesos independientes, podemos entonces decir que será equivalente a maximizar la suma de todas las intenciones de compra.

$$ max\;z= \sum_{i\in\; sEncuestados}\sum_{j\in\; sDrivers} \beta_0 + \beta_j x_j $$

Y por último, modificamos la variable independiente para tener en cuenta el valor inicial de percepción de los encuestados y su incremento:

$$ max\;z= \sum_{i\in\; sEncuestados}\sum_{j\in\; sDrivers} \beta_j (pPercepcion_{i,j} + vIncrementoPercepcion_j) $$

Los coeficientes $\beta$ del modelo de regresión logística los llamaremos $pBeta$ en el de optimización.

Sets:

  • $sDrivers$: cardinalidad 5 {precio, combustible, innovación, fiabilidad, diseño}

  • $sEncuestados$: cardinalidad 8000, el número de encuestados de nuestro set

Parámetros:

  • $pPrecioIncremento_{\:sDrivers}$: precio asociado al incremento porcentual de cada driver.

  • $pPercepcion_{\:sEncuestados,\; sDrivers}$: percepción de cada driver por cada encuestado.

  • $pBetas_{sDrivers}$: coeficiente de cada driver de compra.

Variable de decisión:

  • $vIncrementoPercepcion_{\:sDrivers}$: variable de decisión con los puntos porcentuales de mejora que la acción de marketing va a proporcionar.
In [28]:
# Definición del problema
model = pyo.ConcreteModel()

# sets
model.sDrivers = pyo.Set(initialize = feature_labels)
model.sEncuestados = pyo.Set(initialize = ["p_{}".format(i) for i in range(X_train.shape[0])])
In [29]:
df_percepcion=pd.DataFrame(X_train, columns = feature_labels, index = ["p_{}".format(i) for i in range(X_train.shape[0])])
df_percepcion
Out[29]:
diseño consumo fiabilidad innovacion precio
p_0 0.1 0.3 0.3 0.9 0.8
p_1 0.5 0.2 0.0 0.8 0.2
p_2 0.3 0.3 0.6 0.7 0.6
p_3 0.6 0.7 0.8 0.3 0.8
p_4 0.1 0.8 0.5 0.9 0.5
... ... ... ... ... ...
p_7995 0.0 0.3 0.2 0.7 0.9
p_7996 0.7 0.6 0.1 0.2 0.9
p_7997 0.4 0.9 0.4 0.8 0.9
p_7998 0.2 0.4 0.9 0.0 0.2
p_7999 0.8 0.2 0.1 0.8 0.4

8000 rows × 5 columns

In [30]:
# parametros

model.pBetas = pyo.Param(model.sDrivers, initialize = dict(zip(feature_labels, clf.coef_.reshape(-1))))

def load_perception(model, encuesta, driver):
        return df_percepcion[driver][encuesta]
    
model.pPercepcion = pyo.Param(model.sEncuestados, model.sDrivers, initialize = load_perception)
In [31]:
model.pBetas.display()
pBetas : Size=5, Index=sDrivers, Domain=Any, Default=None, Mutable=False
    Key        : Value
       consumo : 10.200367900456106
        diseño :  5.239903907249989
    fiabilidad :  4.376929041693824
    innovacion :  5.653408459329742
        precio :  18.58460482370923
In [32]:
for i in model.pPercepcion.items():
    break
i, model.pPercepcion[('p_7998','innovacion')]
Out[32]:
((('p_0', 'diseño'), 0.1), 0.0)

A continuación, vamos a integrar en el modelo los costes de las actividades de marketing. Recordemos que tenemos un presupuesto de 1000 u.m. y potencialmente podemos mejorar 50 puntos por driver hasta un total de 250 puntos.

El coste de mejora de 1 punto de percepción será para cada driver:

  • Diseño: 10 u.m.

  • Consumo: 21 u.m.

  • Fiabilidad: 12 u.m.

  • Innovación: 15 u.m.

  • Precio: 36 u.m.

Recordemos que nuestros driver están escalados entre 0 y 1, por lo que un incremento unitario, escalado sería de 0.01.

In [33]:
model.pPrecioIncremento = pyo.Param(
                            model.sDrivers,
                            initialize = dict(zip(feature_labels, [10,21,12,15,36]))
                          )
In [34]:
model.pPrecioIncremento.display() 
pPrecioIncremento : Size=5, Index=sDrivers, Domain=Any, Default=None, Mutable=False
    Key        : Value
       consumo :    21
        diseño :    10
    fiabilidad :    12
    innovacion :    15
        precio :    36

Es momento de integrar nuestra variable de decisión, que recordemos podrá ir desde 0 (no mejoramos ese driver) hasta una mejora máxima de 50 puntos. Además, supondremos que las mejoras serán en unidades completas, por lo que la variable de decisión será de tipo entero.

In [35]:
model.vIncrementoPercepcion = pyo.Var(model.sDrivers, domain=pyo.NonNegativeIntegers, bounds=(0,50))
In [36]:
model.vIncrementoPercepcion.display()
vIncrementoPercepcion : Size=5, Index=sDrivers
    Key        : Lower : Value : Upper : Fixed : Stale : Domain
       consumo :     0 :  None :    50 : False :  True : NonNegativeIntegers
        diseño :     0 :  None :    50 : False :  True : NonNegativeIntegers
    fiabilidad :     0 :  None :    50 : False :  True : NonNegativeIntegers
    innovacion :     0 :  None :    50 : False :  True : NonNegativeIntegers
        precio :     0 :  None :    50 : False :  True : NonNegativeIntegers

Del mismo modo, tenemos que integrar la restricción presupuestaria, es decir, que el coste total de las mejoras incrementales no supere nuestro budget de 1000 u.m.

In [37]:
max_budget = 1000

model.ctBudget = pyo.Constraint(
                    expr= pyo.quicksum(model.vIncrementoPercepcion[i]*model.pPrecioIncremento[i] \
                                       for i in model.sDrivers)<=max_budget
                 )

Por último, implementamos la función objetivo descrita anteriormente.

In [38]:
model.obj = pyo.Objective(
                sense = pyo.maximize, 
                expr = pyo.quicksum(
                        (0.01*model.vIncrementoPercepcion[j]+model.pPercepcion[(i,j)])*model.pBetas[j] \
                        for i in model.sEncuestados for j in model.sDrivers
                        )
            )

Resolución del problema de optimización y análisis de resultados


In [39]:
opt = pyo.SolverFactory('cbc')
opt.solve(model) 
Out[39]:
{'Problem': [{'Name': 'unknown', 'Lower bound': 200497.39182216, 'Upper bound': 200497.39182216, 'Number of objectives': 1, 'Number of constraints': 1, 'Number of variables': 5, 'Number of binary variables': 0, 'Number of integer variables': 5, 'Number of nonzeros': 5, 'Sense': 'maximize'}], 'Solver': [{'Status': 'ok', 'User time': -1.0, 'System time': 0.0, 'Wallclock time': 0.01, 'Termination condition': 'optimal', 'Termination message': 'Model was solved to optimality (subject to tolerances), and an optimal solution is available.', 'Statistics': {'Branch and bound': {'Number of bounded subproblems': 0, 'Number of created subproblems': 0}, 'Black box': {'Number of iterations': 2}}, 'Error rc': 0, 'Time': 0.020097732543945312}], 'Solution': [OrderedDict([('number of solutions', 0), ('number of solutions displayed', 0)])]}
In [40]:
model.vIncrementoPercepcion.display()
vIncrementoPercepcion : Size=5, Index=sDrivers
    Key        : Lower : Value : Upper : Fixed : Stale : Domain
       consumo :     0 :   0.0 :    50 : False : False : NonNegativeIntegers
        diseño :     0 :  46.0 :    50 : False : False : NonNegativeIntegers
    fiabilidad :     0 :   0.0 :    50 : False : False : NonNegativeIntegers
    innovacion :     0 :   0.0 :    50 : False : False : NonNegativeIntegers
        precio :     0 :  15.0 :    50 : False : False : NonNegativeIntegers
In [41]:
model.ctBudget.display()
ctBudget : Size=1
    Key  : Lower : Body   : Upper
    None :  None : 1000.0 : 1000.0

Tras comprobar la validez de los resultados, el resultado de la optimización nos indica que la mejor estrategia consiste en mejorar la percepción del diseño prácticamente al máximo, la del consumo de manera marginal y la del precio en 13 puntos para maximizar la intención de compra.

Análisis del impacto


Para finalizar, vamos a comparar el impacto de nuestras iniciativas de marketing con los resultados iniciales de las encuestas. Para ello, modificaremos las percepciones de los encuestados con los incrementos logrados:

  • Precio: +13

  • Consumo: +2

  • Diseño: +49

Es importante prestar atención ya que ninguna percepción debería superar el valor del 100%.

In [42]:
feature_labels
Out[42]:
['diseño', 'consumo', 'fiabilidad', 'innovacion', 'precio']
In [43]:
increments = [0.49, 0.02, 0.00, 0.00, 0.13]
In [44]:
X_impact = X_test + increments
X_impact
Out[44]:
array([[1.39, 0.22, 0.2 , 0.2 , 0.43],
       [0.79, 0.02, 0.4 , 0.1 , 0.83],
       [1.19, 0.92, 0.  , 0.7 , 1.03],
       ...,
       [1.09, 0.32, 0.1 , 0.1 , 0.73],
       [0.69, 0.62, 0.  , 0.1 , 0.23],
       [1.29, 0.92, 0.7 , 0.  , 0.93]])
In [45]:
X_impact_corregido = np.where(X_impact > 1.0, 1.0, X_impact)
X_impact_corregido
Out[45]:
array([[1.  , 0.22, 0.2 , 0.2 , 0.43],
       [0.79, 0.02, 0.4 , 0.1 , 0.83],
       [1.  , 0.92, 0.  , 0.7 , 1.  ],
       ...,
       [1.  , 0.32, 0.1 , 0.1 , 0.73],
       [0.69, 0.62, 0.  , 0.1 , 0.23],
       [1.  , 0.92, 0.7 , 0.  , 0.93]])

Para analizar el impacto, tenemos que tener en cuenta la incertidumbre asociada al propio modelo predictivo, ya que independientemente del resultado de la optimización, partimos de una tasa inicial de falsos positivos y negativos, que en este caso es cercana al 4% en cada caso.

Podríamos optar por una perspectiva pesimista, reduciendo en ese 4% las intenciones positivas de compra tras la optimización como una buena referencia del impacto de la iniciativa.

In [46]:
# Cálculo de las decisiones previas y posteriores a la optimización
decisiones_optimizadas = clf.predict(X_impact_corregido)
decisiones_iniciales = clf.predict(X_test)
decisiones_reales = y_test

# Obtención del factor de corrección como las discrepancias entre las decisiones reales y las del modelo de 
# regresión logística, teniendo en cuenta falsos positivos y falsos negativos
correccion = sum(decisiones_iniciales!=decisiones_reales)/len(decisiones_iniciales)

# Cálculo del impacto
impacto = (sum(decisiones_optimizadas)/sum(decisiones_iniciales))*(1-correccion)

print("Se obtuvo una mejora del {:.2f}%".format(100*(impacto-1)))
Se obtuvo una mejora del 43.85%

Conclusiones


En este artículo hemos explorado cómo, partiendo de encuestas de clientes potenciales y gracias a las analíticas predictiva y prescriptiva, podemos ser capaces de aumentar la intención de compra en un 43.85%.

En casos de negocio reales, la primera etapa de obtención de un modelo predictivo es crucial, ya que la ideoneidad de dicho modelo es determinante en el enfoque de la etapa de optimización posterior.

¿Cómo citar este documento?

Optimización del presupuesto en campañas de marketing con analítica predictiva y prescriptiva by Francisco Espiga, available under a CC BY-NC-SA 4.0 at https://www.cienciadedatos.net/documentos/py31-optimizacion-presupuesto-campañas-marketing.html DOI


¿Te ha gustado el artículo? Tu ayuda es importante

Mantener un sitio web tiene unos costes elevados, tu contribución me ayudará a seguir generando contenido divulgativo gratuito. ¡Muchísimas gracias! 😊


Creative Commons Licence
This work by Francisco Espiga is licensed under a Creative Commons Attribution 4.0 International License.