Condividi tramite


Esercitazione: Usare R per creare, valutare e assegnare un punteggio a un modello di stima della varianza

Questa esercitazione presenta un esempio end-to-end di un flusso di lavoro di data science Synapse in Microsoft Fabric. Lo scenario crea un modello per prevedere se i clienti di una banca abbandonano. Il tasso di abbandono, o tasso di attrito, rappresenta il tasso a cui i clienti di una banca terminano il loro rapporto con la banca.

Questa esercitazione comprende i seguenti passaggi:

  • Installare librerie personalizzate
  • Caricare i dati
  • Comprendere ed elaborare i dati tramite l'analisi esplorativa dei dati
  • Usare scikit-learn e LightGBM per eseguire il training di modelli di Machine Learning
  • Valutare e salvare il modello di apprendimento automatico finale
  • Visualizzare le prestazioni del modello con le visualizzazioni di Power BI

Prerequisiti

Seguire la procedura in un notebook

È possibile scegliere una di queste opzioni per seguire la procedura in un notebook:

  • Aprire ed eseguire il notebook predefinito nell'esperienza di data science di Synapse.
  • Caricare il notebook da GitHub nell'esperienza di data science di Synapse.

Aprire il notebook predefinito

Il notebook di abbandono dei clienti di esempio accompagna questa esercitazione.

  1. Per aprire il notebook di esempio per questa esercitazione, seguire le istruzioni riportate in Preparare il sistema per le esercitazioni sull'analisi scientifica dei dati.

  2. Assicurarsi di collegare una lakehouse al notebook prima di iniziare a eseguire il codice.

Importare il notebook da GitHub

Il notebook AIsample - R Bank Customer Churn.ipynb accompagna questa esercitazione.

Passaggio 1: Installare librerie personalizzate

Per lo sviluppo di modelli di apprendimento automatico o l'analisi dei dati ad hoc, potrebbe essere necessario installare rapidamente una libreria personalizzata per la sessione di Apache Spark. Sono disponibili due opzioni per installare le librerie.

  • Usare le risorse di installazione inline, ad esempio install.packages e devtools::install_version, per installare solo nel notebook corrente.
  • In alternativa, è possibile creare un ambiente Fabric, installare librerie da origini pubbliche o caricarvi librerie personalizzate e quindi l'amministratore dell'area di lavoro può collegare l'ambiente come predefinito per l'area di lavoro. Tutte le librerie nell'ambiente diventano quindi disponibili per l'uso in qualsiasi notebook e definizione del processo Spark nell'area di lavoro. Per altre informazioni sugli ambienti, vedere Creare, configurare e usare un ambiente in Microsoft Fabric.

In questa esercitazione usare install.packages() per installare le librerie imbalance e randomForest. Impostare quiet su TRUE per rendere l'output più conciso:

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

Passaggio 2: Caricare i dati

Il set di dati in churn.csv contiene lo stato di abbandono di 10.000 clienti, insieme a 14 attributi che includono:

  • Punteggio sul credito
  • Posizione geografica (Germania, Francia, Spagna)
  • Sesso (maschio, femmina)
  • Età
  • Anzianità (numero di anni in cui la persona è stata cliente in quella banca)
  • Saldo del conto
  • Stipendio stimato
  • Numero di prodotti acquistati da un cliente tramite la banca
  • Stato della carta di credito (se un cliente ha o meno una carta di credito)
  • Stato membro attivo (se la persona è un cliente della banca attivo o meno)

Il set di dati include anche le colonne numero di riga, ID cliente e cognome del cliente. I valori in queste colonne non devono influenzare la decisione di un cliente di lasciare la banca.

Un evento di chiusura del conto bancario del cliente definisce l’abbandono per il cliente. La colonna del set di dati Exited si riferisce all'abbandono del cliente. Dato che questi attributi hanno poco contesto, non sono necessarie informazioni di base sul set di dati. Si vuole comprendere come questi attributi contribuiscono allo stato Exited.

Su 10.000 clienti, solo i clienti del 2037 (circa il 20%) hanno lasciato la banca. A causa del rapporto di squilibrio tra classi, è consigliabile generare la generazione di dati sintetici.

Questa tabella mostra un esempio di anteprima dei dati churn.csv:

CustomerID Cognome CreditScore Geografia Genere Età Mandato Saldo NumOfProducts HasCrCard IsActiveMember EstimatedSalary Usciti
15634602 Hargrave 619 Francia Femmina 42 2 0.00 1 1 1 101348.88 1
15647311 Hill 608 Spagna Femmina 41 1 83807.86 1 0 1 112542.58 0

Scaricare il set di dati e caricarlo nel lakehouse

Importante

Aggiungere un lakehouse al notebook prima di eseguirlo. In caso contrario, verrà generato un errore.

Questo codice scarica una versione disponibile pubblicamente del set di dati e quindi archivia i dati in un lakehouse di Fabric:

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.")

Avviare la registrazione del tempo necessario per eseguire questo notebook:

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

Leggere i dati di data non elaborati dal lakehouse

Questo codice legge i dati non elaborati dalla sezione File del lakehouse:

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

Passaggio 3: Eseguire l'analisi esplorativa dei dati

Visualizzazione di dati non elaborati

Usare i comandi head() o str() per eseguire un'esplorazione preliminare dei dati non elaborati:

head(rdf)

Eseguire la pulizia iniziale dei dati

Convertire R DataFrame in un Spark DataFrame. Queste operazioni sul dataframe Spark puliscono il set di dati non elaborato:

  • Eliminare le righe con dati mancanti in tutte le colonne
  • Eliminare le righe duplicate tra le colonne RowNumber e CustomerId
  • Escludere la colonna RowNumber, CustomerId e 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)

Esplorare il dataframe Spark con il comando display:

display(df_clean)

Questo codice determina gli attributi categorici, numerici e di destinazione:

# 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)

Per semplificare l'elaborazione e la visualizzazione, convertire il dataframe Spark pulito in un dataframe R:

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

Visualizzare il riepilogo in cinque numeri

Usare i box plot per visualizzare il riepilogo a cinque numeri (punteggio minimo, primo quartile, mediano, terzo quartile, punteggio massimo) per gli attributi numerici:

# 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
}

Screenshot that shows box plots for credit score and age.Screenshot che mostra i tracciati box per il punteggio di credito e l'età.

# 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
}

Screenshot that shows box plots for numeric variables.Screenshot che mostra i tracciati box per le variabili numeriche.

Visualizzare la distribuzione dei clienti usciti e non usciti

Visualizzare la distribuzione dei clienti usciti rispetto ai clienti non usciti, tra gli attributi categorici:

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)
}

Screenshot that shows bar plots split by geography and gender.Screenshot che mostra i tracciati a barre suddivisi per geografia e sesso.

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)
}

Screenshot that shows bar charts for customers that have a credit card and are active members.Screenshot che mostra grafici a barre per i clienti con carta di credito e membri attivi.

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)
}

Screenshot that shows bar charts for number of products and tenure.Screenshot che mostra grafici a barre per il numero di prodotti e tenure.

Visualizzare la distribuzione degli attributi numerici

Usare un istogramma per visualizzare la distribuzione della frequenza degli attributi numerici:

# 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
}

Screenshot of a graph that shows the distribution of credit score and age.Screenshot di un grafico che mostra la distribuzione del punteggio di credito e dell'età.

# 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
}

Screenshot of a graph that shows the distribution of numeric variables.Screenshot di un grafico che mostra la distribuzione delle variabili numeriche.

Eseguire l'ingegneria delle funzionalità

Questa progettazione di funzionalità genera nuovi attributi in base agli attributi correnti:

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)))

Eseguire la codifica one-hot

Usare la codifica one-hot per convertire gli attributi categorici in attributi numerici, per inserirli nel modello di Machine Learning:

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

Creare una tabella differenziale per generare il report di 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))

Riepilogo delle osservazioni dell'analisi esplorativa dei dati

  • La maggior parte dei clienti proviene dalla Francia. La Spagna ha il tasso di abbandono più basso, rispetto alla Francia e alla Germania.
  • La maggior parte dei clienti ha carte di credito
  • Alcuni clienti superano i 60 anni di età e hanno punteggi di credito inferiori a 400. Tuttavia, non possono essere considerati come outlier
  • Pochi clienti hanno più di due prodotti bancari
  • I clienti inattivi hanno un tasso di abbandono più elevato
  • Il sesso e gli anni di anzianità hanno un impatto minimo sulla decisione di un cliente di chiudere un conto bancario

Passaggio 4: Eseguire il training del modello

Con i dati disponibili, è ora possibile definire il modello. Applicare modelli Random Forest e LightGBM. Usare randomForest e LightGBM per implementare i modelli con poche righe di codice.

Caricare la tabella delta dal lakehouse. È possibile usare altre tabelle delta che considerano il lakehouse come origine.

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

Importare randomForest e LightGBM:

library(randomForest)
library(lightgbm)

Preparare i set di dati di training e test:

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)

Applicare SMOTE al set di dati di training

La classificazione sbilanciata presenta un problema, poiché contiene troppi esempi della classe di minoranza per un modello per apprendere efficacemente il limite decisionale. Per gestire questo problema, Synthetic Minority Oversampling Technique (SMOTE) è la tecnica più usata per sintetizzare nuovi campioni per la classe di minoranza. Accedere a SMOTE con la libreria imblearn installata nel passaggio 1.

Applicare SMOTE solo al set di dati di training. È necessario lasciare il set di dati di test nella distribuzione originale sbilanciata per ottenere un'approssimazione valida delle prestazioni del modello sui dati originali. Questo esperimento rappresenta la situazione in produzione.

In primo luogo, mostrare la distribuzione delle classi nel set di dati per apprendere quale classe è la classe di minoranza. Il rapporto tra la classe di minoranza e la classe di maggioranza è definito come imbalance Ratio nella libreria 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)))

Nel set di dati di training:

  • Positive class(Exited) fa riferimento alla classe di minoranza, che accetta il 20,34% del set di dati.
  • Negative class(Non-Exited) fa riferimento alla classe di maggioranza, che accetta il 79,66% del set di dati.

La cella successiva riscrive la funzione di sovracampionamento della libreria imbalance per generare un set di dati bilanciato:

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
}

Per altre informazioni su SMOTE, vedere le risorse Pacchetto imbalance e Lavorare con insiemi di dati sbilanciati sul sito web CRAN.

Sovracampionare il set di dati di training

Usare la funzione di sovracampionamento appena definita per eseguire il sovracampionamento nel set di dati di training:

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))

Eseguire il training del modello

Usare una foresta casuale per eseguire il training del modello, con quattro funzionalità:

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))

Usare una foresta casuale per eseguire il training del modello, con sei funzionalità:

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))

Eseguire il training del modello 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))

Passaggio 5: valutare e salvare il modello di apprendimento automatico finale

Valutare le prestazioni dei modelli salvati nel set di dati di test:

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)

Mostrare veri/falsi positivi/negativi con una matrice di confusione. Sviluppare uno script per tracciare la matrice di confusione per valutare l'accuratezza della classificazione:

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)
}

Creare una matrice di confusione per il classificatore di foresta casuale, con quattro funzionalità:

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]

Screenshot of a graph that shows a confusion matrix for random forest with four features.Screenshot di un grafico che mostra una matrice di confusione per una foresta casuale con quattro funzionalità.

Creare una matrice di confusione per il classificatore di foresta casuale, con sei funzionalità:

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]

Screenshot of a graph that shows a confusion matrix for random forest with six features.Screenshot di un grafico che mostra una matrice di confusione per una foresta casuale con sei funzionalità.

Creare una matrice di confusione per 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]

Screenshot of a graph that shows a confusion matrix for LightGBM.Screenshot di un grafico che mostra una matrice di confusione per LightGBM.

Salvare i risultati per Power BI

Salvare il frame differenziale nel lakehouse per spostare i risultati della stima del modello in una visualizzazione di 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))

Passaggio 6: Accedere alle visualizzazioni in Power BI

Accedere alla tabella salvata in Power BI:

  1. A sinistra selezionare Hub dati OneLake
  2. Selezionare il lakehouse aggiunto a questo notebook
  3. Nella sezione Apri questo lakehouse selezionare Apri
  4. Nella barra multifunzione selezionare Nuovo modello semantico. Selezionare df_pred_results e quindi Continua per creare un nuovo modello semantico di Power BI collegato alle stime
  5. Nella parte superiore della pagina del set di dati selezionare Nuovo report per aprire la pagina di creazione di report di Power BI.

Lo screenshot seguente mostra alcune visualizzazioni di esempio. Il pannello dati mostra le tabelle e le colonne differenziali da selezionare da una tabella. Dopo aver selezionato l'asse e il valore (y) appropriati, è possibile scegliere i filtri e le funzioni. Ad esempio, è possibile scegliere una somma o una media della colonna della tabella.

Nota

Lo screenshot è un esempio illustrato che mostra l'analisi dei risultati della stima salvata in Power BI. Per un caso d'uso reale della varianza dei clienti, gli utenti della piattaforma potrebbero avere bisogno di un'idea più approfondita delle visualizzazioni da creare, in base alle competenze in materia e a ciò che il team di analisi aziendale e dell’organizzazione hanno standardizzato come metriche.

Screenshot that shows a Power BI dashboard of the data.Screenshot che mostra la dashboard di Power BI dei dati.

Il report di Power BI mostra che i clienti che usano più di due prodotti bancari hanno un tasso di abbandono più elevato. Tuttavia, pochi clienti avevano più di due prodotti. Vedere il tracciato nel pannello in basso a sinistra. La banca dovrebbe raccogliere più dati, ma anche analizzare altre funzionalità correlate a più prodotti.

I clienti della banca in Germania hanno un tasso di abbandono più elevato rispetto ai clienti in Francia e Spagna. Vedere il tracciato nel pannello in basso a destra. In base ai risultati del report, un'indagine sui fattori che hanno incoraggiato i clienti a lasciare potrebbe aiutare.

Ci sono più clienti di mezza età (tra i 25 e i 45 anni). I clienti tra i 45 e i 60 anni tendono a uscire di più.

Infine, i clienti con punteggi di credito più bassi lasciano la banca per altri istituti finanziari. La banca dovrebbe esplorare i modi per incoraggiare i clienti con punteggi di credito e saldi di conto più bassi a rimanere.

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