Determinar una puntuación de tendencia mediante un modelo predictivo generado por aprendizaje automático

Con Query Service puede aprovechar los modelos predictivos, como las puntuaciones de tendencia, creados en su plataforma de aprendizaje automático para analizar los datos de los Experience Platform.

En esta guía se explica cómo utilizar el servicio de consulta para enviar datos a la plataforma de aprendizaje automático con el fin de formar un modelo en un bloc de notas computacional. El modelo entrenado se puede aplicar a los datos utilizando SQL para predecir la tendencia de un cliente a comprar para cada visita.

Primeros pasos

Como parte de este proceso requiere que forme un modelo de aprendizaje automático, en este documento se da por hecho que tiene conocimientos prácticos de uno o más entornos de aprendizaje automático.

Este ejemplo utiliza Jupyter Notebook como entorno de desarrollo. Aunque hay muchas opciones disponibles, Jupyter Notebook se recomienda porque es una aplicación web de código abierto que tiene bajos requisitos de cálculo. Puede ser descargado del sitio oficial.

Si aún no lo ha hecho, siga los pasos para conectar Jupyter Notebook con Adobe Experience Platform Query Service antes de continuar con esta guía.

Las bibliotecas utilizadas en este ejemplo incluyen:

python=3.6.7
psycopg2
sklearn
pandas
matplotlib
numpy
tqdm

Importación de tablas de análisis de Platform en Jupyter Notebook import-analytics-tables

Para generar un modelo de puntuación de tendencia, se debe importar una proyección de los datos de análisis almacenados en Platform en Jupyter Notebook. Desde una Python 3 Jupyter Notebook Conectados al servicio de consultas, los siguientes comandos importan un conjunto de datos de comportamiento del cliente de Luma, una tienda de ropa ficticia. Como los datos de Platform se almacenan con el formato Experience Data Model (XDM), se debe generar un objeto JSON de muestra que se ajuste a la estructura del esquema. Consulte la documentación para obtener instrucciones sobre cómo generar el objeto JSON de muestra.

El Jupyter Notebook panel con varios comandos resaltados.

El resultado muestra una vista tabularizada de todas las columnas del conjunto de datos de comportamiento de Luma dentro del Jupyter Notebook panel.

La salida tabularizada del conjunto de datos de comportamiento del cliente importado de Luma dentro de Jupyter Notebook.

Preparación de los datos para el aprendizaje automático prepare-data-for-machine-learning

Se debe identificar una columna de destino para entrenar un modelo de aprendizaje automático. Como la tendencia a comprar es el objetivo para este caso de uso, la variable analytic_action se elige como columna de destino en los resultados de Luma. El valor productPurchase es el indicador de una compra del cliente. El purchase_value y purchase_num también se eliminan, ya que están directamente relacionadas con la acción de compra del producto.

Los comandos para realizar estas acciones son los siguientes:

#define the target label for prediction
df['target'] = (df['analytic_action'] == 'productPurchase').astype(int)
#remove columns that are dependent on the label
df.drop(['analytic_action','purchase_value'],axis=1,inplace=True)

A continuación, los datos del conjunto de datos de Luma deben transformarse en representaciones adecuadas. Se requieren dos pasos:

  1. Transforme las columnas que representan números en columnas numéricas. Para ello, convierta explícitamente el tipo de datos en la variable dataframe.
  2. Transforme también columnas categóricas en columnas numéricas.
#convert columns that represent numbers
num_cols = ['purchase_num', 'value_cart', 'value_lifetime']
df[num_cols] = df[num_cols].apply(pd.to_numeric, errors='coerce')

Una técnica llamada una codificación activa se utiliza para convertir las variables de datos categóricas para su uso con algoritmos de aprendizaje automático y profundo. Esto, a su vez, mejora las predicciones así como la precisión de clasificación de un modelo. Utilice el Sklearn para representar cada valor categórico en una columna independiente.

from sklearn.preprocessing import OneHotEncoder

#get the categorical columns
cat_columns = list(set(df.columns) - set(num_cols + ['target']))

#get the dataframe with categorical columns only
df_cat = df.loc[:,cat_columns]

#initialize sklearn's OneHotEncoder
enc = OneHotEncoder(handle_unknown='ignore')

#fit the data into the encoder
enc.fit(df_cat)

#define OneHotEncoder's columns names
ohc_columns = [[c+'='+c_ for c_ in cat] for c,cat in zip(cat_columns,enc.categories_)]
ohc_columns = [item for sublist in ohc_columns for item in sublist]

#finalize the data input to the ML models
X = pd.DataFrame( np.concatenate((enc.transform(df_cat).toarray(),df[num_cols]),axis=1),
                 columns =  ohc_columns + num_cols)

#define target column
y = df['target']

Los datos definidos como X se tabulará y aparecerá de la siguiente manera:

La salida tabularizada de X en Jupyter Notebook.

Ahora que los datos necesarios para el aprendizaje automático están disponibles, puede ajustar los modelos de aprendizaje automático preconfigurados en Pythonde sklearn biblioteca. Logistics Regression se utiliza para entrenar el modelo de tendencia y permite ver la precisión de los datos de prueba. En este caso, es de aproximadamente el 85 %.

El Logistic Regression y el método de división tren-prueba, utilizado para estimar el rendimiento de los algoritmos de aprendizaje automático, se importan en el siguiente bloque de código:

from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.33, random_state=42)

clf = LogisticRegression(max_iter=2000, random_state=0).fit(X_train, y_train)

print("Test data accuracy: {}".format(clf.score(X_test, y_test)))

La precisión de los datos de prueba es de 0,8518518518518519.

A través del uso de la regresión logística, puede visualizar las razones de una compra y ordenar las funciones que determinan la tendencia por su importancia jerárquica en órdenes descendentes. Las primeras columnas denotan una mayor causalidad que conduce al comportamiento de compra. Estas últimas columnas indican los factores que no conducen al comportamiento de compra.

El código para visualizar los resultados como dos gráficos de barras es el siguiente:

from matplotlib import pyplot as plt

#get feature importance as a sorted list of columns
feature_importance = np.argsort(-clf.coef_[0])
top_10_features_purchase_names = X.columns[feature_importance[:10]]
top_10_features_purchase_values = clf.coef_[0][feature_importance[:10]]
top_10_features_not_purchase_names = X.columns[feature_importance[-10:]]
top_10_features_not_purchase_values = clf.coef_[0][feature_importance[-10:]]

#plot the figures
fig, (ax1, ax2) = plt.subplots(1, 2,figsize=(10,5))

ax1.bar(np.arange(10),top_10_features_purchase_values)
ax1.set_xticks(np.arange(10))
ax1.set_xticklabels(top_10_features_purchase_names,rotation = 90)
ax1.set_ylim([np.min(clf.coef_[0])-0.1,np.max(clf.coef_[0])+0.1])
ax1.set_title("Top 10 features to define \n a propensity to purchase")

ax2.bar(np.arange(10),top_10_features_not_purchase_values, color='#E15750')
ax2.set_xticks(np.arange(10))
ax2.set_xticklabels(top_10_features_not_purchase_names,rotation = 90)
ax2.set_ylim([np.min(clf.coef_[0])-0.1,np.max(clf.coef_[0])+0.1])
ax2.set_title("Top 10 features to define \n a propensity to NOT purchase")

plt.show()

A continuación se muestra una visualización de los resultados en un gráfico de barras verticales:

La visualización de las 10 principales funciones que definen una tendencia a comprar o no comprar.

En el gráfico de barras se pueden discernir varios patrones. Los puntos de venta (POS) y los temas de llamada del canal como reembolso son los factores más importantes que deciden el comportamiento de compra. Mientras que los temas de llamadas como quejas y facturas son funciones importantes para definir el comportamiento de no compra. Se trata de perspectivas cuantificables y procesables que los especialistas en marketing pueden aprovechar para llevar a cabo campañas de marketing con el fin de abordar la tendencia a la compra de estos clientes.

Utilice el servicio de consulta para aplicar el modelo entrenado use-query-service-to-apply-trained-model

Una vez creado el modelo entrenado, debe aplicarse a los datos que tiene en Experience Platform. Para ello, la lógica de la canalización de aprendizaje automático debe convertirse a SQL. Los dos componentes clave de esta transición son los siguientes:

  • En primer lugar, SQL debe reemplazar a Logistics Regression para obtener la probabilidad de una etiqueta de predicción. El modelo de regresión logística produjo el modelo de regresión y = wX + c donde pesa w e interceptar c son la salida del modelo. Las funciones SQL se pueden utilizar para multiplicar los pesos y obtener una probabilidad.

  • En segundo lugar, el proceso de ingeniería logrado en Python con una codificación hot también debe incorporarse a SQL. Por ejemplo, en la base de datos original, tenemos geo_county para almacenar la provincia, pero la columna se convierte en geo_county=Bexar, geo_county=Dallas, geo_county=DeKalb. La siguiente instrucción SQL realiza la misma transformación, donde w1, w2, y w3 podrían sustituirse por las ponderaciones aprendidas del modelo en Python:

SELECT  CASE WHEN geo_state = 'Bexar' THEN FLOAT(w1) ELSE 0 END AS f1,
        CASE WHEN geo_state = 'Dallas' THEN FLOAT(w2) ELSE 0 END AS f2,
        CASE WHEN geo_state = 'Bexar' THEN FLOAT(w3) ELSE 0 END AS f3,

Para las funciones numéricas, puede multiplicar directamente las columnas con los pesos, tal como se ve en la instrucción SQL a continuación.

SELECT FLOAT(purchase_num) * FLOAT(w4) AS f4,

Una vez obtenidos los números, pueden transferirse a una función sigmoidea donde el algoritmo de Regresión Logística produce las predicciones finales. En la declaración siguiente, intercept es el número de intersección en la regresión.

SELECT CASE WHEN 1 / (1 + EXP(- (f1 + f2 + f3 + f4 + FLOAT(intercept)))) > 0.5 THEN 1 ELSE 0 END AS Prediction;

Un ejemplo de extremo a extremo

En una situación en la que tiene dos columnas (c1 y c2), si c1 tiene dos categorías, la Logistic Regression algoritmo entrenado con la siguiente función:

y = 0.1 * "c1=category 1"+ 0.2 * "c1=category 2" +0.3 * c2+0.4

El equivalente en SQL es el siguiente:

SELECT
  CASE WHEN 1 / (1 + EXP(- (f1 + f2 + f3 + FLOAT(0.4)))) > 0.5 THEN 1 ELSE 0 END AS Prediction
FROM
  (
    SELECT
      CASE WHEN c1 = 'Cateogry 1' THEN FLOAT(0.1) ELSE 0 END AS f1,
      CASE WHEN c1 = 'Cateogry 2' THEN FLOAT(0.2) ELSE 0 END AS f2,
      FLOAT(c2) * FLOAT(0.3) AS f3
    FROM TABLE
  )

El Python el código para automatizar el proceso de traducción es el siguiente:

def generate_lr_inference_sql(ohc_columns, num_cols, clf, db):
    features_sql = []
    category_sql_text = "case when {col} = '{val}' then float({coef}) else 0 end as f{name}"
    numerical_sql_text = "float({col}) * float({coef}) as f{name}"
    for i, (column, coef) in enumerate(zip(ohc_columns+num_cols, clf.coef_[0])):
        if i < len(ohc_columns):
            col,val = column.split('=')
            val = val.replace("'","%''%")
            sql = category_sql_text.format(col=col,val=val,coef=coef,name=i+1)
        else:
            sql = numerical_sql_text.format(col=column,coef=coef,name=i+1)
        features_sql.append(sql)
    features_sum = '+'.join(['f{}'.format(i) for i in range(1,len(features_sql)+1)])
    final_sql = '''
    select case when 1/(1 + EXP(-({features} + float({intercept})))) > 0.5 then 1 else 0 end as Prediction
    from
        (select {cols}
        from {db})
    '''.format(features=features_sum,cols=",".join(features_sql),intercept=clf.intercept_[0],db=db)
    return final_sql

Cuando se utiliza SQL para deducir la base de datos, el resultado es el siguiente:

sql = generate_lr_inference_sql(ohc_columns, num_cols, clf, "fdu_luma_raw")
cur.execute(sql)
samples = [r for r in cur]
colnames = [desc[0] for desc in cur.description]
pd.DataFrame(samples,columns=colnames)

Los resultados tabulados muestran la tendencia a comprar para cada sesión de cliente con 0 lo que significa que no hay tendencia a comprar y 1 lo que significa una tendencia confirmada a comprar.

Los resultados tabularizados de la inferencia de la base de datos utilizando SQL.

Trabajo en datos de ejemplo: Bootstrapping working-on-sampled-data

En caso de que el tamaño de los datos sea demasiado grande para que el equipo local almacene los datos para la formación de modelos, puede tomar muestras en lugar de los datos completos del servicio de consultas. Para saber cuántos datos se necesitan muestrear desde el servicio de consultas, puede aplicar una técnica llamada bootstrapping. En este sentido, el bootstrapping significa que el modelo se entrena varias veces con varias muestras, y se inspecciona la varianza de las precisiones del modelo entre diferentes muestras. Para ajustar el ejemplo del modelo de tendencia anterior, primero, encapsule todo el flujo de trabajo de aprendizaje automático en una función. El código es el siguiente:

def end_to_end_pipeline(df):

    #define the target label for prediction
    df['target'] = (df['analytic_action'] == 'productPurchase').astype(int)
    #remove columns that are dependent on the label
    df.drop(['analytic_action','purchase_value'],axis=1,inplace=True)

    num_cols = ['purchase_num','value_cart','value_lifetime']
    df[num_cols] = df[num_cols].apply(pd.to_numeric, errors='coerce')

    #get the categorical columns
    cat_columns = list(set(df.columns) - set(num_cols + ['target']))

    #get the dataframe with categorical columns only
    df_cat = df.loc[:,cat_columns]

    #initialize sklearn's One Hot Encoder
    enc = OneHotEncoder(handle_unknown='ignore')

    #fit the data into the encoder
    enc.fit(df_cat)

    #define one hot encoder's columns names
    ohc_columns = [[c+'='+c_ for c_ in cat] for c,cat in zip(cat_columns,enc.categories_)]
    ohc_columns = [item for sublist in ohc_columns for item in sublist]

    #finalize the data input to the ML models
    X = pd.DataFrame( np.concatenate((enc.transform(df_cat).toarray(),df[num_cols]),axis=1),
                     columns =  ohc_columns + num_cols)

    #define target column
    y = df['target']

    X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.33, random_state=42)

    clf = LogisticRegression(max_iter=2000,random_state=0).fit(X_train, y_train)

    return clf.score(X_test, y_test)

Esta función se puede ejecutar varias veces en un bucle, por ejemplo, 10 veces. La diferencia con el código anterior es que ahora el ejemplo no se toma de toda la tabla, sino solo de una muestra de filas. Por ejemplo, el código de ejemplo siguiente solo contiene 1000 filas. Se pueden almacenar las precisiones de cada iteración.

from tqdm import tqdm

bootstrap_accuracy = []
for i in tqdm(range(100)):

    #sample data from QS
    cur.execute('''SELECT *
    FROM fdu_luma_raw
    ORDER BY random()
    LIMIT 1000
    ''')
    samples = [r for r in cur]
    colnames = [desc[0] for desc in cur.description]
    df_samples = pd.DataFrame(samples,columns=colnames)
    df_samples.fillna(0,inplace=True)

    #train the propensity model with sampled data and output its accuracy
    bootstrap_accuracy.append(end_to_end_pipeline(df_samples))

bootstrap_accuracy = np.sort(bootstrap_accuracy)

A continuación, se ordenan las precisiones del modelo arrancado. Después de lo cual, los cuantiles 10 y 90 de las precisiones del modelo se convierten en un intervalo de confianza del 95 % para las precisiones del modelo con el tamaño de muestra dado.

El comando print para mostrar el intervalo de confianza de la puntuación de tendencia.

La figura anterior indica que si solo toma 1000 filas para entrenar sus modelos, puede esperar que la precisión caiga entre aproximadamente el 84 % y el 88 %. Puede ajustar la variable LIMIT en las consultas del servicio de consultas en función de sus necesidades para garantizar el rendimiento de los modelos.

recommendation-more-help
ccf2b369-4031-483f-af63-a93b5ae5e3fb