Compartir a través de


Tutorial: Uso de R para crear, evaluar y puntuar un modelo de predicción de abandono

En este tutorial se presenta un ejemplo completo de un flujo de trabajo de ciencia de datos de Synapse en Microsoft Fabric. El escenario crea un modelo para predecir si los clientes bancarios abandonan o no. La tasa de renovación, o la tasa de atrición, implica la tasa a la que los clientes bancarios terminan su negocio con el banco.

En este tutorial se describen estos pasos:

  • Instalación de bibliotecas personalizadas
  • Carga de los datos
  • Descripción y procesamiento de los datos a través del análisis de datos exploratorios
  • Uso de scikit-learn y LightGBM para entrenar modelos de aprendizaje automático
  • Evaluación y guardado del modelo de aprendizaje automático final
  • Mostrar el rendimiento del modelo con visualizaciones de Power BI

Prerrequisitos

Sigue el desarrollo en un cuaderno

Puede elegir una de estas opciones para seguir en un cuaderno:

  • Abra y ejecute el cuaderno integrado en la experiencia de ciencia de datos de Synapse.
  • Cargue el cuaderno desde GitHub en la experiencia de ciencia de datos de Synapse.

Abra el cuaderno integrado.

Customer Churn (abandono de clientes) es el cuaderno de ejemplo que acompaña a este tutorial.

  1. Para abrir el cuaderno de ejemplo de este tutorial, siga las instrucciones de Preparar el sistema para tutoriales de ciencia de datos.

  2. Asegúrese de adjuntar un almacén de lago de datos al cuaderno antes de empezar a ejecutar el código.

Importación del cuaderno desde GitHub

AIsample - R Bank Customer Churn.ipynb es el cuaderno que acompaña a este tutorial.

Paso 1: Instalación de bibliotecas personalizadas

Para el desarrollo de modelos de Machine Learning o el análisis de datos ad hoc, es posible que tenga que instalar rápidamente una biblioteca personalizada para la sesión de Apache Spark. Tiene dos opciones para instalar bibliotecas.

  • Use recursos de instalación en línea, por ejemplo, install.packages y devtools::install_version, para instalar solo en el cuaderno actual.
  • Como alternativa, puede crear un entorno de Fabric, instalar bibliotecas desde orígenes públicos o cargar bibliotecas personalizadas en él y, a continuación, el administrador del área de trabajo puede asociar el entorno como valor predeterminado para el área de trabajo. Todas las bibliotecas del entorno estarán disponibles para su uso en los cuadernos y las definiciones de trabajo de Spark en el área de trabajo. Para obtener más información sobre los entornos, consulte crear, configurar y usar un entorno en Microsoft Fabric.

En este tutorial, use install.packages() para instalar las bibliotecas de imbalance y randomForest. Establezca quiet en TRUE para que la salida sea más concisa:

# Install imbalance for SMOTE
install.packages("imbalance", quiet = TRUE)
# Install the random forest algorithm
install.packages("randomForest", quiet=TRUE)

Paso 2: Cargar los datos

El conjunto de datos de churn.csv contiene el estado de abandono de 10.000 clientes, junto con 14 atributos que incluyen:

  • Puntuación de crédito
  • Ubicación geográfica (Alemania, Francia, España)
  • Género (masculino, femenino)
  • Edad
  • Antigüedad (número de años que la persona era cliente en ese banco)
  • Saldo de la cuenta
  • Salario estimado
  • Número de productos que un cliente compró a través del banco
  • Estado de la tarjeta de crédito (si un cliente tiene o no una tarjeta de crédito)
  • Estado de miembro activo (independientemente de si la persona es un cliente bancario activo)

El conjunto de datos también incluye columnas de número de fila, identificador de cliente y apellidos del cliente. Los valores de estas columnas no deben influir en la decisión de un cliente de abandonar el banco.

Un evento de cierre de cuenta bancaria de un cliente define la pérdida de ese cliente. El conjunto de datos Exited columna hace referencia al abandono del cliente. Dado que tenemos poco contexto sobre estos atributos, no necesitamos información general sobre el conjunto de datos. Queremos comprender cómo contribuyen estos atributos al estado Exited.

De los 10.000 clientes, solo 2037 clientes (alrededor de 20%) dejaron el banco. Debido al desequilibrio de clases, recomendamos generar datos sintéticos.

En esta tabla se muestra un ejemplo de vista previa de los datos de churn.csv:

ID de Cliente Apellido Puntuación de crédito Geografía Género Edad Tenencia Equilibrio NumOfProducts HasCrCard EsMiembroActivo SalarioEstimado Cerrado
15634602 Hargrave 619 Francia Mujer 42 2 0.00 1 1 1 101348.88 1
15647311 Hill 608 España Femenino 41 1 83807.86 1 0 1 112542.58 0

Descarga del conjunto de datos y carga en un almacén de lago de datos

Importante

Agregue un almacén de lago de datos al cuaderno antes de ejecutarlo. Si no lo hace, se producirá un error.

Este código descarga una versión disponible públicamente del conjunto de datos y, a continuación, almacena esos datos en una instancia de Fabric Lakehouse:

library(fs)
library(httr)

remote_url <- "https://sdkstorerta.blob.core.windows.net/churnblob"
file_list <- c("churn.csv")
download_path <- "/lakehouse/default/Files/churn/raw"

if (!dir_exists("/lakehouse/default")) {
  stop("Default lakehouse not found, please add a lakehouse and restart the session.")
}
dir_create(download_path, recurse= TRUE)
for (fname in file_list) {
  if (!file_exists(paste0(download_path, "/", fname))) {
    r <- GET(paste0(remote_url, "/", fname), timeout(30))
    writeBin(content(r, "raw"), paste0(download_path, "/", fname))
  }
}
print("Downloaded demo data files into lakehouse.")

Inicie la grabación del tiempo necesario para ejecutar este cuaderno:

# Record the notebook running time
ts <- as.numeric(Sys.time())

Lectura de datos sin procesar desde el almacén de lago de datos

Este código lee datos sin procesar de la sección Archivos del lago de datos:

fname <- "churn.csv"
download_path <- "/lakehouse/default/Files/churn/raw"
rdf <- readr::read_csv(paste0(download_path, "/", fname))

Paso 3: Realizar análisis de datos exploratorios

Mostrar datos sin procesar

Use los comandos head() o str() para realizar una exploración preliminar de los datos sin procesar:

head(rdf)

Realizar la limpieza inicial de datos

Debe convertir el dataframe de R en un dataframe de Spark. Estas operaciones en spark DataFrame limpian el conjunto de datos sin procesar:

  • Eliminar las filas que tienen datos faltantes en todas las columnas
  • Quite las filas duplicadas en las columnas RowNumber y CustomerId
  • Quite las columnas RowNumber, CustomerIdy Surname
# Transform the R DataFrame to a Spark DataFrame
df <- as.DataFrame(rdf)

clean_data <- function(df) {
  sdf <- df %>%
    # Drop rows that have missing data across all columns
    na.omit() %>%
    # Drop duplicate rows in columns: 'RowNumber', 'CustomerId'
    dropDuplicates(c("RowNumber", "CustomerId")) %>%
    # Drop columns: 'RowNumber', 'CustomerId', 'Surname'
    SparkR::select("CreditScore", "Geography", "Gender", "Age", "Tenure", "Balance", "NumOfProducts", "HasCrCard", "IsActiveMember", "EstimatedSalary", "Exited")
  return(sdf)
}

df_clean <- clean_data(df)

Explore el DataFrame de Spark con el comando display:

display(df_clean)

Este código determina los atributos categóricos, numéricos y de destino:

# Determine the dependent (target) attribute
dependent_variable_name <- "Exited"
print(dependent_variable_name)

# Obtain the distinct values for each column
exprs = lapply(names(df_clean), function(x) alias(countDistinct(df_clean[[x]]), x))
# Use do.call to splice the aggregation expressions to aggregate function
distinct_value_number <- SparkR::collect(do.call(agg, c(x = df_clean, exprs)))

# Determine the categorical attributes
categorical_variables <- names(df_clean)[sapply(names(df_clean), function(col) col %in% c("0") || distinct_value_number[[col]] <= 5 && !(col %in% c(dependent_variable_name)))]
print(categorical_variables)

# Determine the numerical attributes
numeric_variables <- names(df_clean)[sapply(names(df_clean), function(col) coltypes(SparkR::select(df_clean, col)) == "numeric" && distinct_value_number[[col]] > 5)]
print(numeric_variables)

Para facilitar el procesamiento y la visualización, convierta el dataframe de Spark limpio en un dataframe de R:

# Transform the Spark DataFrame to an R DataFrame
rdf_clean <- SparkR::collect(df_clean)

Mostrar el resumen de cinco números

Use gráficos de cuadros para mostrar el resumen de cinco números (puntuación mínima, primer cuartil, mediana, tercer cuartil, puntuación máxima) para los atributos numéricos:

# Set the overall layout of the graphics window
par(mfrow = c(2, 1), 
    mar = c(2, 1, 2, 1)) # Margin size

for(item in numeric_variables[1:2]){
    # Create a box plot
    boxplot(rdf_clean[, item], 
            main = item, 
            col = "darkgreen", 
            cex.main = 1.5, # Title size
            cex.lab = 1.3, # Axis label size
            cex.axis = 1.2,
            horizontal = TRUE) # Axis size
}

Captura de pantalla que muestra gráficos de cuadros para la puntuación de crédito y la antigüedad.

# Set the overall layout of the graphics window
par(mfrow = c(3, 1), 
    mar = c(2, 1, 2, 1)) # Margin size

for(item in numeric_variables[3:5]){
    # Create a box plot
    boxplot(rdf_clean[, item], 
            main = item, 
            col = "darkgreen", 
            cex.main = 1.5, # Title size
            cex.lab = 1.3, # Axis label size
            cex.axis = 1.2,
            horizontal = TRUE) # Axis size
}

Captura de pantalla que muestra gráficos de cuadros para variables numéricas.

Mostrar la distribución de clientes que se han dado de baja y clientes que no se han dado de baja

Mostrar la distribución de clientes que se han dado de baja frente a clientes que permanecen, según los atributos categóricos.

attr_list <- c('Geography', 'Gender', 'HasCrCard', 'IsActiveMember', 'NumOfProducts', 'Tenure')
par(mfrow = c(2, 1), 
    mar = c(2, 1, 2, 1)) # Margin size
for (item in attr_list[1:2]) {
    counts <- table(rdf_clean$Exited, rdf_clean[,item])
    barplot(counts, main=item, col=c("darkblue","yellow"), 
            cex.main = 1.5, # Title size
            cex.axis = 1.2,
            legend = rownames(counts), beside=TRUE)
}

Captura de pantalla que muestra los trazados de barras divididos por geografía y género.

par(mfrow = c(2, 1), 
    mar = c(2, 2, 2, 1)) # Margin size
for (item in attr_list[3:4]) {
    counts <- table(rdf_clean$Exited, rdf_clean[,item])
    barplot(counts, main=item, col=c("darkblue","yellow"), 
            cex.main = 1.5, # Title size
            cex.axis = 1.2,
            legend = rownames(counts), beside=TRUE)
}

Captura de pantalla que muestra los gráficos de barras para los clientes que tienen una tarjeta de crédito y son miembros activos.

par(mfrow = c(2, 1), 
    mar = c(2, 1, 2, 1)) # Margin size
for (item in attr_list[5:6]) {
    counts <- table(rdf_clean$Exited, rdf_clean[,item])
    barplot(counts, main=item, col=c("darkblue","yellow"), 
            cex.main = 1.5, # Title size
            cex.axis = 1.2,
            legend = rownames(counts), beside=TRUE)
}

Captura de pantalla que muestra gráficos de barras para el número de productos y antigüedad.

Mostrar la distribución de atributos numéricos

Use un histograma para mostrar la distribución de frecuencia de los atributos numéricos:

# Set the overall layout of the graphics window
par(mfrow = c(2, 1), 
    mar = c(2, 4, 2, 4) + 0.1) # Margin size

# Create a histogram
for (item in numeric_variables[1:2]) {
    hist(rdf_clean[, item], 
         main = item, 
         col = "darkgreen", 
         xlab = item,
         cex.main = 1.5, # Title size
         cex.axis = 1.2,
         breaks = 20) # Number of bins
}

Captura de pantalla de un gráfico que muestra la distribución de la puntuación de crédito y la edad.

# Set the overall layout of the graphics window
par(mfrow = c(3, 1), 
    mar = c(2, 4, 2, 4) + 0.1) # Margin size

# Create a histogram
for (item in numeric_variables[3:5]) {
    hist(rdf_clean[, item], 
         main = item, 
         col = "darkgreen", 
         xlab = item,
         cex.main = 1.5, # Title size
         cex.axis = 1.2,
         breaks = 20) # Number of bins
}

Captura de pantalla de un gráfico que muestra la distribución de variables numéricas.

Realizar ingeniería de funciones

Esta ingeniería de características genera nuevos atributos basados en atributos actuales:

rdf_clean$NewTenure <- rdf_clean$Tenure / rdf_clean$Age
rdf_clean$NewCreditsScore <- as.numeric(cut(rdf_clean$CreditScore, breaks=quantile(rdf_clean$CreditScore, probs=seq(0, 1, by=1/6)), include.lowest=TRUE, labels=c(1, 2, 3, 4, 5, 6)))
rdf_clean$NewAgeScore <- as.numeric(cut(rdf_clean$Age, breaks=quantile(rdf_clean$Age, probs=seq(0, 1, by=1/8)), include.lowest=TRUE, labels=c(1, 2, 3, 4, 5, 6, 7, 8)))
rdf_clean$NewBalanceScore <- as.numeric(cut(rank(rdf_clean$Balance), breaks=quantile(rank(rdf_clean$Balance, ties.method = "first"), probs=seq(0, 1, by=1/5)), include.lowest=TRUE, labels=c(1, 2, 3, 4, 5)))
rdf_clean$NewEstSalaryScore <- as.numeric(cut(rdf_clean$EstimatedSalary, breaks=quantile(rdf_clean$EstimatedSalary, probs=seq(0, 1, by=1/10)), include.lowest=TRUE, labels=c(1:10)))

Realización de una codificación activa

Use la codificación one-hot para convertir los atributos categóricos en atributos numéricos, para introducirlos en el modelo de aprendizaje automático:

rdf_clean <- cbind(rdf_clean, model.matrix(~Geography+Gender-1, data=rdf_clean))
rdf_clean <- subset(rdf_clean, select = - c(Geography, Gender))

Creación de una tabla delta para generar el informe de Power BI

table_name <- "rdf_clean"
# Create a Spark DataFrame from an R DataFrame
sparkDF <- as.DataFrame(rdf_clean)
write.df(sparkDF, paste0("Tables/", table_name), source = "delta", mode = "overwrite")
cat(paste0("Spark DataFrame saved to delta table: ", table_name))

Resumen de las observaciones del análisis de datos exploratorios

  • La mayoría de los clientes son de Francia. España tiene la tasa de renovación más baja, en comparación con Francia y Alemania.
  • La mayoría de los clientes tienen tarjetas de crédito
  • Algunos clientes son mayores de 60 años y tienen puntuaciones de crédito por debajo de 400. Sin embargo, no se pueden considerar valores atípicos
  • Pocos clientes tienen más de dos productos bancarios
  • Los clientes inactivos tienen una tasa de renovación más alta
  • Los años de género y antigüedad tienen poco impacto en la decisión de un cliente de cerrar una cuenta bancaria

Paso 4: Realizar el entrenamiento del modelo

Con los datos implementados, ahora puede definir el modelo. Aplicar modelos de Bosque aleatorio y LightGBM. Use randomForest y LightGBM para implementar los modelos con algunas líneas de código.

Cargue la tabla delta desde el lago de datos. Puede usar otras tablas delta teniendo en cuenta el almacén de lago como origen.

SEED <- 12345
rdf_clean <- read.df("Tables/rdf_clean", source = "delta")
df_clean <- as.data.frame(rdf_clean)

Importar randomForest y LightGBM:

library(randomForest)
library(lightgbm)

Prepare los conjuntos de datos de entrenamiento y prueba:

set.seed(SEED)
y <- factor(df_clean$Exited)
X <- df_clean[, !(colnames(df_clean) %in% c("Exited"))]
split <- base::sample(c(TRUE, FALSE), nrow(df_clean), replace = TRUE, prob = c(0.8, 0.2))
X_train <- X[split,]
X_test <- X[!split,]
y_train <- y[split]
y_test <- y[!split]
train_df <- cbind(X_train, y_train)

Aplicación de SMOTE al conjunto de datos de entrenamiento

La clasificación desequilibrada tiene un problema, ya que tiene demasiado pocos ejemplos de la clase minoritaria para que un modelo aprenda eficazmente el límite de decisión. Para controlar esto, la técnica de sobremuestreo de minorías sintéticas (SMOTE) es el enfoque más utilizado para sintetizar nuevas muestras para la clase minoría. Acceda a SMOTE con la biblioteca imblearn que instaló en el paso 1.

Aplique SMOTE solo al conjunto de datos de entrenamiento. Debe dejar el conjunto de datos de prueba en su distribución desequilibrada original para obtener una aproximación válida del rendimiento del modelo en los datos originales. Este experimento representa la situación en producción.

En primer lugar, muestre la distribución de clases en el conjunto de datos para saber qué clase es la clase minoría. La relación entre la clase minoría y la clase mayoritaria se define como imbalance Ratio en la biblioteca imbalance.

original_ratio <- imbalance::imbalanceRatio(train_df, classAttr = "y_train")
message(sprintf("Original imbalance ratio is %.2f%% as {Size of minority class}/{Size of majority class}.", original_ratio * 100))
message(sprintf("Positive class(Exited) takes %.2f%% of the dataset.", round(sum(train_df$y_train == 1)/nrow(train_df) * 100, 2)))
message(sprintf("Negative class(Non-Exited) takes %.2f%% of the dataset.", round(sum(train_df$y_train == 0)/nrow(train_df) * 100, 2)))

En el conjunto de datos de entrenamiento:

  • Positive class(Exited) hace referencia a la clase minoría, que toma 20,34% del conjunto de datos.
  • Negative class(Non-Exited) hace referencia a la clase de mayoría, que toma 79,66% del conjunto de datos.

La celda siguiente vuelve a escribir la función oversample de la biblioteca de imbalance, para generar un conjunto de datos equilibrado:

binary_oversample <- function(train_df, X_train, y_train, class_Attr = "Class"){
    negative_num <- sum(y_train == 0) # Compute the number of the negative class
    positive_num <- sum(y_train == 1) # Compute the number of the positive class
    difference_num <- abs(negative_num - positive_num) # Compute the difference between the negative and positive classes
    originalShape <- imbalance:::datasetStructure(train_df, class_Attr) # Get the original dataset schema
    new_samples <- smotefamily::SMOTE(X_train, y_train, dup_size = ceiling(max(negative_num, positive_num)/min(negative_num, positive_num))) # Use SMOTE to oversample
    new_samples <- new_samples$syn_data # Get the synthetic data
    new_samples <- new_samples[base::sample(1:nrow(new_samples), size = difference_num), ] # Sample and shuffle the synthetic data
    new_samples <- new_samples[, -ncol(new_samples)] # Remove the class column
    new_samples <- imbalance:::normalizeNewSamples(originalShape, new_samples) # Normalize the synthetic data
    new_train_df <- rbind(train_df, new_samples) # Concatenate original and synthetic data by row
    new_train_df <- new_train_df[base::sample(nrow(new_train_df)), ] # Shuffle the training dataset
    new_train_df
}

Para obtener más información sobre SMOTE, vea los recursos Paquete imbalance y Trabajo con conjuntos de datos desequilibrados en el sitio web de CRAN.

Sobremuestreo del conjunto de datos de entrenamiento

Use la función oversample recién definida para realizar el sobremuestreo en el conjunto de datos de entrenamiento:

library(dplyr)
new_train_df <- binary_oversample(train_df, X_train, y_train, class_Attr="y_train")
smote_ratio <- imbalance::imbalanceRatio(new_train_df, classAttr = "y_train")
message(sprintf("Imbalance ratio after using smote is %.2f%%\n", smote_ratio * 100))

Entrenamiento del modelo

Use un bosque aleatorio para entrenar el modelo, con cuatro características:

set.seed(1)
rfc1_sm <- randomForest(y_train ~ ., data = new_train_df, ntree = 500, mtry = 4, nodesize = 3)
y_pred <- predict(rfc1_sm, X_test, type = "response")
cr_rfc1_sm <- caret::confusionMatrix(y_pred, y_test)
cm_rfc1_sm <- table(y_pred, y_test)
roc_auc_rfc1_sm <- pROC::auc(pROC::roc(as.numeric(y_test), as.numeric(y_pred)))
print(paste0("The auc is ", roc_auc_rfc1_sm))

Use un bosque aleatorio para entrenar el modelo, con seis características:

rfc2_sm <- randomForest(y_train ~ ., data = new_train_df, ntree = 500, mtry = 6, nodesize = 3)
y_pred <- predict(rfc2_sm, X_test, type = "response")
cr_rfc2_sm <- caret::confusionMatrix(y_pred, y_test)
cm_rfc2_sm <- table(y_pred, y_test)
roc_auc_rfc2_sm <- pROC::auc(pROC::roc(as.numeric(y_test), as.numeric(y_pred)))
print(paste0("The auc is ", roc_auc_rfc2_sm))

Entrenamiento del modelo con LightGBM:

set.seed(42)
X_train <- new_train_df[, !(colnames(new_train_df) %in% c("y_train"))]
y_train <- as.numeric(as.character(new_train_df$y_train))
y_test <- as.numeric(as.character(y_test))
lgbm_sm_model <- lgb.train(list(objective = "binary", learning_rate = 0.1, max_delta_step = 2, nrounds = 100, max_depth = 10, eval_metric = "logloss"), lgb.Dataset(as.matrix(X_train), label = as.vector(y_train)), valids = list(test = lgb.Dataset(as.matrix(X_test), label = as.vector(as.numeric(y_test)))))
y_pred <- as.numeric(predict(lgbm_sm_model, as.matrix(X_test)) > 0.5)
accuracy <- mean(y_pred == as.vector(y_test))
cr_lgbm_sm <- caret::confusionMatrix(as.factor(y_pred), as.factor(as.vector(y_test)))
cm_lgbm_sm <- table(y_pred, as.vector(y_test))
roc_auc_lgbm_sm <- pROC::auc(pROC::roc(as.vector(y_test), y_pred))
print(paste0("The auc is ", roc_auc_lgbm_sm))

Paso 5: Evaluación y guardado del modelo de aprendizaje automático final

Evalúe el rendimiento de los modelos guardados en el conjunto de datos de prueba:

ypred_rfc1_sm <- predict(rfc1_sm, X_test, type = "response")
ypred_rfc2_sm <- predict(rfc2_sm, X_test, type = "response")
ypred_lgbm1_sm <- as.numeric(predict(lgbm_sm_model, as.matrix(X_test)) > 0.5)

Mostrar verdaderos/falsos positivos/negativos con una matriz de confusión. Desarrolle un script para trazar la matriz de confusión para evaluar la precisión de la clasificación:

plot_confusion_matrix <- function(cm, classes, normalize=FALSE, title='Confusion matrix', cmap=heat.colors(10)) {
  if (normalize) {
    cm <- cm / rowSums(cm)
  }
  op <- par(mar = c(6,6,3,1))
  image(1:nrow(cm), 1:ncol(cm), t(cm[nrow(cm):1,]), col = cmap, xaxt = 'n', yaxt = 'n', main = title, xlab = "Prediction", ylab = "Reference")
  axis(1, at = 1:nrow(cm), labels = classes, las = 2)
  axis(2, at = 1:ncol(cm), labels = rev(classes))
  for (i in seq_len(nrow(cm))) {
    for (j in seq_len(ncol(cm))) {
      text(i, ncol(cm) - j + 1, cm[j,i], cex = 0.8)
    }
  }
  par(op)
}

Cree una matriz de confusión para el clasificador de bosque aleatorio, con cuatro características:

cfm <- table(y_test, ypred_rfc1_sm)
plot_confusion_matrix(cfm, classes=c('Non Churn','Churn'), title='Random Forest with features of 4')
tn <- cfm[1,1]
fp <- cfm[1,2]
fn <- cfm[2,1]
tp <- cfm[2,2]

Captura de pantalla de un gráfico que muestra una matriz de confusión para el bosque aleatorio con cuatro características.

Cree una matriz de confusión para el clasificador de bosque aleatorio, con seis características:

cfm <- table(y_test, ypred_rfc2_sm)
plot_confusion_matrix(cfm, classes=c('Non  Churn','Churn'), title='Random Forest with features of 6')
tn <- cfm[1,1]
fp <- cfm[1,2]
fn <- cfm[2,1]
tp <- cfm[2,2]

Captura de pantalla de un gráfico que muestra una matriz de confusión para el bosque aleatorio con seis características.

Cree una matriz de confusión para LightGBM:

cfm <- table(y_test, ypred_lgbm1_sm)
plot_confusion_matrix(cfm, classes=c('Non Churn','Churn'), title='LightGBM')
tn <- cfm[1,1]
fp <- cfm[1,2]
fn <- cfm[2,1]
tp <- cfm[2,2]

Captura de pantalla de un gráfico que muestra una matriz de confusión para LightGBM.

Guardar resultados para Power BI

Guarde el marco delta en lakehouse para mover los resultados de predicción del modelo a una visualización de Power BI:

df_pred <- X_test
df_pred$y_test <- y_test
df_pred$ypred_rfc1_sm <- ypred_rfc1_sm
df_pred$ypred_rfc2_sm <- ypred_rfc2_sm
df_pred$ypred_lgbm1_sm <- ypred_lgbm1_sm

table_name <- "df_pred_results"
sparkDF <- as.DataFrame(df_pred)
write.df(sparkDF, paste0("Tables/", table_name), source = "delta", mode = "overwrite", overwriteSchema = "true")

cat(paste0("Spark DataFrame saved to delta table: ", table_name))

Paso 6: Acceso a visualizaciones en Power BI

Acceda a la tabla guardada en Power BI:

  1. A la izquierda, seleccione centro de datos de OneLake
  2. Seleccione el almacén de lago de datos que agregó a este cuaderno
  3. En la sección Abrir este almacén de lago de datos, seleccione Abrir
  4. En la cinta de opciones, seleccione Nuevo modelo semántico. Seleccione df_pred_resultsy, a continuación, seleccione Continuar para crear un nuevo modelo semántico de Power BI vinculado a las predicciones.
  5. En las herramientas de la parte superior de la página del conjunto de datos, seleccione Nuevo informe para abrir la página de creación de informes de Power BI.

En la captura de pantalla siguiente se muestran algunas visualizaciones de ejemplo. El panel de datos muestra las tablas y columnas delta que se van a seleccionar de una tabla. Después de seleccionar el eje de categorías (x) y el eje de valores (y) adecuados, puede elegir los filtros y las funciones. Por ejemplo, puede elegir una suma o media de la columna de tabla.

Nota

La captura de pantalla es un ejemplo ilustrado que muestra el análisis de los resultados de la predicción guardada en Power BI. Para un caso de uso real sobre la deserción de clientes, los usuarios de la plataforma podrían necesitar una idea más completa sobre las visualizaciones que se deben crear, basándose tanto en la experiencia en la materia como en lo que la organización y el equipo de análisis empresarial de la empresa han estandarizado como métricas.

Captura de pantalla que muestra un panel de Power BI de los datos.

El informe de Power BI muestra que los clientes que usan más de dos de los productos bancarios tienen una tasa de renovación más alta. Sin embargo, pocos clientes tenían más de dos productos. (Vea el trazado en el panel inferior izquierdo). El banco debe recopilar más datos, pero también investigar otras características que se correlacionan con más productos.

Los clientes bancarios en Alemania tienen una tasa de abandono más alta que los clientes de Francia y España. (Vea el trazado en el panel inferior derecho). En función de los resultados del informe, una investigación sobre los factores que animan a los clientes a salir podrían ayudar.

Hay más clientes de mediana edad (entre 25 y 45). Los clientes entre 45 y 60 tienden a salir más.

Por último, los clientes con puntuaciones de crédito más bajas probablemente dejarían el banco para otras instituciones financieras. El banco debe explorar formas de animar a los clientes con puntuaciones de crédito más bajas y saldos de cuentas para mantenerse con el banco.

# Determine the entire runtime
cat(paste0("Full run cost ", as.integer(Sys.time() - ts), " seconds.\n"))