Dela via


Självstudie: Använda R för att skapa, utvärdera och bedöma en modell för bedrägeriidentifiering

I den här handledningen visas ett heltäckande exempel på ett Synapse Data Science-arbetsflöde i Microsoft Fabric. I det här scenariot skapar vi en modell för bedrägeriidentifiering i R med maskininlärningsalgoritmer som tränats på historiska data. Sedan använder vi modellen för att identifiera framtida bedrägliga transaktioner.

Den här handledningen omfattar följande steg:

  • Installera anpassade bibliotek
  • Läs in data
  • Förstå och bearbeta data med undersökande dataanalys och visa användningen av funktionen Fabric Data Wrangler
  • Träna maskininlärningsmodeller med LightGBM
  • Använda maskininlärningsmodellerna för bedömning och förutsägelser

Förutsättningar

Följ med i en anteckningsbok

Du kan välja något av följande alternativ för att följa med i en notebook:

  • Öppna och kör den inbyggda notebook-filen i Synapse Data Science-upplevelsen
  • Ladda upp din notebook-fil från GitHub till Synapse Data Science-upplevelsen

Öppna den inbyggda notebook-filen

Exempelexemplet Bedrägeriidentifiering notebook-fil medföljer den här självstudien.

  1. Om du vill öppna exempelanteckningsboken för den här självstudien följer du anvisningarna i Förbereda systemet för självstudier för datavetenskap.

  2. Se till att bifoga ett lakehouse till notebook- innan du börjar köra kod.

Importera anteckningsboken från GitHub

Den AIsample – R Fraud Detection.ipynb anteckningsboken medföljer den här handledningen.

Steg 1: Installera anpassade bibliotek

För utveckling av maskininlärningsmodeller eller ad hoc-dataanalys kan du snabbt behöva installera ett anpassat bibliotek för Apache Spark-sessionen. Du har två alternativ för att installera bibliotek.

  • Använd infogade installationsresurser, till exempel install.packages och devtools::install_version, för att endast installera i din nuvarande anteckningsbok.
  • Du kan också skapa en Infrastrukturmiljö, installera bibliotek från offentliga källor eller ladda upp anpassade bibliotek till den och sedan kan din arbetsyteadministratör koppla miljön som standard för arbetsytan. Alla bibliotek i miljön blir sedan tillgängliga för användning i alla anteckningsböcker och Spark-jobbdefinitioner på arbetsytan. Mer information om miljöer finns i skapa, konfigurera och använda en miljö i Microsoft Fabric.

I den här handledningen använder du install.version() för att installera biblioteket imbalanced-learn.

# Install dependencies
devtools::install_version("bnlearn", version = "4.8")
# Install imbalance for SMOTE
devtools::install_version("imbalance", version = "1.0.2.1")

Steg 2: Läs in datan

Datamängden för bedrägeriidentifiering innehåller kreditkortstransaktioner från september 2013, som europeiska kortinnehavare gjort under loppet av två dagar. Datamängden innehåller endast numeriska funktioner på grund av en PCA-transformering (Principal Component Analysis) som tillämpas på de ursprungliga funktionerna. PCA omvandlade alla funktioner förutom Time och Amount. För att skydda konfidentialiteten kan vi inte tillhandahålla de ursprungliga funktionerna eller mer bakgrundsinformation om datauppsättningen.

Den här informationen beskriver datamängden:

  • Funktionerna V1, V2, V3, ..., V28 är huvudkomponenterna som hämtas med PCA
  • Funktionen Time innehåller de förflutna sekunderna mellan en transaktion och den första transaktionen i datamängden
  • Egenskapen Amount är transaktionsbeloppet. Du kan använda den här funktionen för till exempel beroende, kostnadskänslig inlärning
  • Kolumnen Class är variabeln svar (mål). Den har värdet 1 för bedrägeri och 0 annars

Endast 492 transaktioner, av totalt 284 807 transaktioner, är bedrägliga. Datamängden är mycket obalanserad eftersom minoritetsklassen (bedräglig) endast står för cirka 0,172% av data.

Den här tabellen visar en förhandsgranskning av creditcard.csv data:

Tid V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12 V13 V14 V15 V16 V17 V18 V19 V20 V21 V22 V23 V24 V25 V26 V27 V28 Belopp Klass
0 -1.3598071336738 -0.0727811733098497 2.53634673796914 1.37815522427443 -0.338320769942518 0.462387777762292 0.239598554061257 0.0986979012610507 0.363786969611213 0.0907941719789316 -0.551599533260813 -0.617800855762348 -0.991389847235408 -0.311169353699879 1.46817697209427 -0.470400525259478 0.207971241929242 0.0257905801985591 0.403992960255733 0.251412098239705 -0.018306777944153 0.277837575558899 -0.110473910188767 0.0669280749146731 0.128539358273528 -0.189114843888824 0.133558376740387 -0.0210530534538215 149.62 "0"
0 1,19185711131486 0.26615071205963 0.16648011335321 0.448154078460911 0.0600176492822243 -0.0823608088155687 -0.0788029833323113 0.0851016549148104 -0.255425128109186 -0.166974414004614 1.61272666105479 1.06523531137287 0.48909501589608 -0.143772296441519 0.635558093258208 0,463917041022171 -0.114804663102346 -0.183361270123994 -0.145783041325259 -0.0690831352230203 -0.225775248033138 -0.638671952771851 0.101288021253234 -0.339846475529127 0.167170404418143 0.125894532368176 -0.00898309914322813 0.0147241691924927 2.69 0

Ladda ned datauppsättningen och ladda upp till lakehouse

Definiera dessa parametrar så att du kan använda den här notebook-filen med olika datauppsättningar:

IS_CUSTOM_DATA <- FALSE  # If TRUE, the dataset has to be uploaded manually

IS_SAMPLE <- FALSE  # If TRUE, use only rows of data for training; otherwise, use all data
SAMPLE_ROWS <- 5000  # If IS_SAMPLE is True, use only this number of rows for training

DATA_ROOT <- "/lakehouse/default"
DATA_FOLDER <- "Files/fraud-detection"  # Folder with data files
DATA_FILE <- "creditcard.csv"  # Data file name

Den här koden laddar ned en offentligt tillgänglig version av datamängden och lagrar den sedan i en Fabric lakehouse.

Viktig

Se till att lägga till en lakehouse- i anteckningsboken innan du kör den. Annars får du ett fel.

if (!IS_CUSTOM_DATA) {
    # Download data files into a lakehouse if they don't exist
    library(httr)
    
    remote_url <- "https://synapseaisolutionsa.blob.core.windows.net/public/Credit_Card_Fraud_Detection"
    fname <- "creditcard.csv"
    download_path <- file.path(DATA_ROOT, DATA_FOLDER, "raw")

    dir.create(download_path, showWarnings = FALSE, recursive = TRUE)
    if (!file.exists(file.path(download_path, fname))) {
        r <- GET(file.path(remote_url, fname), timeout(30))
        writeBin(content(r, "raw"), file.path(download_path, fname))
    }
    message("Downloaded demo data files into lakehouse.")
}

Läsa rådatumdata från lakehouse

Den här koden läser rådata från avsnittet Files i lakehouse:

data_df <- read.csv(file.path(DATA_ROOT, DATA_FOLDER, "raw", DATA_FILE))

Steg 3: Utföra undersökande dataanalys

Använd kommandot display för att visa statistik på hög nivå för datauppsättningen:

display(as.DataFrame(data_df, numPartitions = 3L))
# Print dataset basic information
message(sprintf("records read: %d", nrow(data_df)))
message("Schema:")
str(data_df)
# If IS_SAMPLE is True, use only SAMPLE_ROWS of rows for training
if (IS_SAMPLE) {
    data_df = sample_n(data_df, SAMPLE_ROWS)
}

Skriv ut fördelningen av klasser i datauppsättningen:

# The distribution of classes in the dataset
message(sprintf("No Frauds %.2f%% of the dataset\n", round(sum(data_df$Class == 0)/nrow(data_df) * 100, 2)))
message(sprintf("Frauds %.2f%% of the dataset\n", round(sum(data_df$Class == 1)/nrow(data_df) * 100, 2)))

Den här klassfördelningen visar att de flesta transaktionerna är icke-bedrägliga. Därför krävs förbearbetning av data före modellträning för att undvika överanpassning.

Visa fördelningen av bedrägliga kontra icke-bedragna transaktioner

Visa fördelningen av bedrägliga kontra icke-bedrägliga transaktioner med ett diagram för att visa klassobalansen i datauppsättningen:

library(ggplot2)

ggplot(data_df, aes(x = factor(Class), fill = factor(Class))) +
  geom_bar(stat = "count") +
  scale_x_discrete(labels = c("no fraud", "fraud")) +
  ggtitle("Class Distributions \n (0: No Fraud || 1: Fraud)") +
  theme(plot.title = element_text(size = 10))

Skärmbild som visar ett stapeldiagram över bedrägerier.

Diagrammet visar tydligt obalansen i datauppsättningen:

Visa sammanfattningen med fem nummer

Visa femtalssammanfattningen (minsta poäng, första kvartilen, median, tredje kvartilen och högsta poäng) för transaktionsbeloppet, med rutor:

library(ggplot2)
library(dplyr)

ggplot(data_df, aes(x = as.factor(Class), y = Amount, fill = as.factor(Class))) +
  geom_boxplot(outlier.shape = NA) +
  scale_x_discrete(labels = c("no fraud", "fraud")) +
  ggtitle("Boxplot without Outliers") +
  coord_cartesian(ylim = quantile(data_df$Amount, c(0.05, 0.95)))

Skärmbild som visar rutor för transaktionsbelopp som delas upp efter klass.

För data med hög obalans kan det hända att lådritningar inte visar korrekta insikter. Du kan dock åtgärda problemet med Class obalans först och sedan skapa samma diagram för mer exakta insikter.

Steg 4: Träna och utvärdera modellerna

Här tränar du en LightGBM-modell för att klassificera bedrägeritransaktionerna. Du tränar en LightGBM-modell på både den obalanserade datamängden och den balanserade datamängden. Sedan jämför du prestandan för båda modellerna.

Förbereda tränings- och testdatauppsättningar

Innan träningen delar du upp data till tränings- och testdatauppsättningarna:

# Split the dataset into training and test datasets
set.seed(42)
train_sample_ids <- base::sample(seq_len(nrow(data_df)), size = floor(0.85 * nrow(data_df)))

train_df <- data_df[train_sample_ids, ]
test_df <- data_df[-train_sample_ids, ]

Tillämpa SMOTE på träningsdatauppsättningen

Obalanserad klassificering har ett problem. Den har för få exempel på minoritetsklasser för att en modell effektivt ska kunna lära sig beslutsgränsen. SMOTE (Synthetic Minority Oversampling Technique) kan hantera detta problem. SMOTE är den mest använda metoden för att syntetisera nya exempel för minoritetsklassen. Du kan komma åt SMOTE med hjälp av det imbalance bibliotek som du installerade i steg 1.

Använd endast SMOTE på träningsdatauppsättningen i stället för testdatauppsättningen. När du bedömer modellen med testdata behöver du en uppskattning av modellens prestanda för osedda data i produktionen. För en giltig uppskattning förlitar sig testdata på den ursprungliga obalanserade fördelningen för att representera produktionsdata så nära som möjligt.

# Apply SMOTE to the training dataset
library(imbalance)

# Print the shape of the original (imbalanced) training dataset
train_y_categ <- train_df %>% select(Class) %>% table
message(
    paste0(
        "Original dataset shape ",
        paste(names(train_y_categ), train_y_categ, sep = ": ", collapse = ", ")
    )
)

# Resample the training dataset by using SMOTE
smote_train_df <- train_df %>%
    mutate(Class = factor(Class)) %>%
    oversample(ratio = 0.99, method = "SMOTE", classAttr = "Class") %>%
    mutate(Class = as.integer(as.character(Class)))

# Print the shape of the resampled (balanced) training dataset
smote_train_y_categ <- smote_train_df %>% select(Class) %>% table
message(
    paste0(
        "Resampled dataset shape ",
        paste(names(smote_train_y_categ), smote_train_y_categ, sep = ": ", collapse = ", ")
    )
)

Mer information om SMOTE finns i paketet 'imbalance' och resurserna Hantering av obalanserade dataset på CRAN-webbplatsen.

Träna modellen med LightGBM

Träna LightGBM-modellen med både den obalanserade datamängden och den balanserade datamängden (via SMOTE). Jämför sedan deras prestanda:

# Train LightGBM for both imbalanced and balanced datasets and define the evaluation metrics
library(lightgbm)

# Get the ID of the label column
label_col <- which(names(train_df) == "Class")

# Convert the test dataset for the model
test_mtx <- as.matrix(test_df)
test_x <- test_mtx[, -label_col]
test_y <- test_mtx[, label_col]

# Set up the parameters for training
params <- list(
    objective = "binary",
    learning_rate = 0.05,
    first_metric_only = TRUE
)

# Train for the imbalanced dataset
message("Start training with imbalanced data:")
train_mtx <- as.matrix(train_df)
train_x <- train_mtx[, -label_col]
train_y <- train_mtx[, label_col]
train_data <- lgb.Dataset(train_x, label = train_y)
valid_data <- lgb.Dataset.create.valid(train_data, test_x, label = test_y)
model <- lgb.train(
    data = train_data,
    params = params,
    eval = list("binary_logloss", "auc"),
    valids = list(valid = valid_data),
    nrounds = 300L
)

# Train for the balanced (via SMOTE) dataset   
message("\n\nStart training with balanced data:")
smote_train_mtx <- as.matrix(smote_train_df)
smote_train_x <- smote_train_mtx[, -label_col]
smote_train_y <- smote_train_mtx[, label_col]
smote_train_data <- lgb.Dataset(smote_train_x, label = smote_train_y)
smote_valid_data <- lgb.Dataset.create.valid(smote_train_data, test_x, label = test_y)
smote_model <- lgb.train(
    data = smote_train_data,
    params = params,
    eval = list("binary_logloss", "auc"),
    valids = list(valid = smote_valid_data),
    nrounds = 300L
)

Fastställa funktioners betydelse

Fastställa funktionsvikt för den modell som du har tränat på den obalanserade datamängden:

imp <- lgb.importance(model, percentage = TRUE)
ggplot(imp, aes(x = Frequency, y = reorder(Feature, Frequency), fill = Frequency)) +
  scale_fill_gradient(low="steelblue", high="tomato") +
  geom_bar(stat = "identity") +
  geom_text(aes(label = sprintf("%.4f", Frequency)), hjust = -0.1) +
  theme(axis.text.x = element_text(angle = 90)) +
  xlim(0, max(imp$Frequency) * 1.1)

Skärmbild av ett stapeldiagram som visar funktionsvikt för den obalanserade modellen.

För modellen som du har tränat på den balanserade datamängden via SMOTE, beräkna funktionernas betydelse.

smote_imp <- lgb.importance(smote_model, percentage = TRUE)
ggplot(smote_imp, aes(x = Frequency, y = reorder(Feature, Frequency), fill = Frequency)) +
  geom_bar(stat = "identity") +
  scale_fill_gradient(low="steelblue", high="tomato") +
  geom_text(aes(label = sprintf("%.4f", Frequency)), hjust = -0.1) +
  theme(axis.text.x = element_text(angle = 90)) +
  xlim(0, max(smote_imp$Frequency) * 1.1)

Skärmbild av ett stapeldiagram som visar funktionsvikt för den balanserade modellen.

En jämförelse av dessa diagram visar tydligt att balanserade och obalanserade träningsdatauppsättningar har stora skillnader i funktionernas betydelse.

Utvärdera modellerna

Här utvärderar du de två tränade modellerna:

  • model tränad på obalanserade rådata
  • smote_model har tränats på balanserad data
preds <- predict(model, test_mtx[, -label_col])
smote_preds <- predict(smote_model, test_mtx[, -label_col])

Utvärdera modellprestanda med en förvirringsmatris

En konfusionsmatris visar antalet

  • sanna positiva identifieringar (TP)
  • sanna negativa (TN)
  • falska positiva (FP)
  • falska negativa (FN)

som en modell producerar när den värderas med testdata. För binär klassificering returnerar modellen en 2x2 förvirringsmatris. För klassificering med flera klasser returnerar modellen en nxn förvirringsmatris, där n är antalet klasser.

  1. Använd en förvirringsmatris för att sammanfatta prestanda för de tränade maskininlärningsmodellerna på testdata:

    plot_cm <- function(preds, refs, title) {
        library(caret)
        cm <- confusionMatrix(factor(refs), factor(preds))
        cm_table <- as.data.frame(cm$table)
        cm_table$Prediction <- factor(cm_table$Prediction, levels=rev(levels(cm_table$Prediction)))
    
        ggplot(cm_table, aes(Reference, Prediction, fill = Freq)) +
                geom_tile() +
                geom_text(aes(label = Freq)) +
                scale_fill_gradient(low = "white", high = "steelblue", trans = "log") +
                labs(x = "Prediction", y = "Reference", title = title) +
                scale_x_discrete(labels=c("0", "1")) +
                scale_y_discrete(labels=c("1", "0")) +
                coord_equal() +
                theme(legend.position = "none")
    }
    
  2. Rita sammanblandningsmatrisen för modellen som tränats på den obalanserade datamängden:

    # The value of the prediction indicates the probability that a transaction is fraud
    # Use 0.5 as the threshold for fraud/no-fraud transactions
    plot_cm(ifelse(preds > 0.5, 1, 0), test_df$Class, "Confusion Matrix (Imbalanced dataset)")
    

    Skärmbild av en förvirringsmatris för den obalanserade modellen.

  3. Rita förväxlingsmatrisen för modellen som tränats på den balanserade datamängden.

    plot_cm(ifelse(smote_preds > 0.5, 1, 0), test_df$Class, "Confusion Matrix (Balanced dataset)")
    

    Skärmbild av en förvirringsmatris för den balanserade modellen.

Utvärdera modellprestanda med måtten AUC-ROC och AUPRC

Måttet Arean under ROC-kurvan (AUC-ROC) utvärderar förmågan hos binära klassificerare. Diagrammet AUC-ROC visualiserar kompromissen mellan den sanna positiva frekvensen (TPR) och den falska positiva frekvensen (FPR).

I vissa fall är det mer lämpligt att utvärdera klassificeraren baserat på måttet Area Under the Precision-Recall Curve (AUPRC). AUPRC-kurvan kombinerar dessa priser:

  • Precisionen eller det positiva prediktiva värdet (PPV)
  • Återkallandet, eller TPR
# Use the PRROC package to help calculate and plot AUC-ROC and AUPRC
install.packages("PRROC", quiet = TRUE)
library(PRROC)

Beräkna måtten AUC-ROC och AUPRC

Beräkna och rita måtten AUC-ROC och AUPRC för de två modellerna.

Obalanserad datauppsättning

Beräkna förutsägelserna:

fg <- preds[test_df$Class == 1]
bg <- preds[test_df$Class == 0]

Skriv ut området under AUC-ROC kurva:

# Compute AUC-ROC
roc <- roc.curve(scores.class0 = fg, scores.class1 = bg, curve = TRUE)
print(roc)

Rita AUC-ROC kurvan:

# Plot AUC-ROC
plot(roc)

Skärmbild av ett diagram som visar AUC-ROC kurvan för den obalanserade modellen.

Skriv ut AUPRC-kurvan:

# Compute AUPRC
pr <- pr.curve(scores.class0 = fg, scores.class1 = bg, curve = TRUE)
print(pr)

Plotta AUPRC-kurvan:

# Plot AUPRC
plot(pr)

Skärmbild av ett diagram som visar AUPRC-kurvan för den obalanserade modellen.

Balanserad datauppsättning (via SMOTE)

Beräkna förutsägelserna:

smote_fg <- smote_preds[test_df$Class == 1]
smote_bg <- smote_preds[test_df$Class == 0]

Skriv ut AUC-ROC kurvan:

# Compute AUC-ROC
smote_roc <- roc.curve(scores.class0 = smote_fg, scores.class1 = smote_bg, curve = TRUE)
print(smote_roc)

Rita AUC-ROC kurvan:

# Plot AUC-ROC
plot(smote_roc)

Skärmbild av ett diagram som visar AUC-ROC kurvan för den balanserade modellen.

Skriv ut AUPRC-kurvan:

# Compute AUPRC
smote_pr <- pr.curve(scores.class0 = smote_fg, scores.class1 = smote_bg, curve = TRUE)
print(smote_pr)

Plotta AUPRC-kurvan:

# Plot AUPRC
plot(smote_pr)

Skärmbild av ett diagram som visar AUPRC-kurvan för den balanserade modellen.

De tidigare siffrorna visar tydligt att modellen som tränats på den balanserade datamängden överträffar modellen som tränats på den obalanserade datamängden, för både AUC-ROC- och AUPRC-poäng. Det här resultatet tyder på att SMOTE effektivt förbättrar modellens prestanda när du arbetar med mycket obalanserade data.