Credit Card Fraud Detection Pipeline

Build a dual-model fraud detector comparing IsolationForest vs SMOTE + Random Forest.

Introduction

30 Second Summary

Credit card fraud costs billions every year. The real challenge isn't just detecting it. It's finding the 492 fraudulent transactions hiding among 284,807 legitimate ones.

In this project, you will build a dual-model fraud detection system that compares unsupervised anomaly detection against supervised classification on real transaction data. You'll watch one model struggle with false positives, then see the other crush it by properly leveraging labeled data.

What You'll Build

A Kaggle Notebook where you pit two fraud detection models against each other on real credit card data, then compare their results side-by-side with confusion matrices and Precision-Recall curves that make the winner obvious.

By the end of this project, you'll have:

  • A running notebook that visualizes the extreme 0.172% fraud rate in the dataset, making the class imbalance problem impossible to ignore.
  • Two competing models evaluated with side-by-side confusion matrices and AUPRC scores, so you can explain exactly why one outperforms the other.
  • A reusable imblearn Pipeline that handles SMOTE resampling correctly during training and never during prediction.
  • A documented mapping showing how this fraud detection pattern transfers directly to IoT sensor anomaly detection.
  • Secret Mission: Tune the classification threshold to hit a specific business target of 95% fraud recall while minimizing false alarms.

Are there any prerequisites?

This project assumes intermediate Python knowledge and basic familiarity with pandas DataFrames and ML concepts like train/test splits and classification. You'll also need a free Kaggle account.

Before We Start

Before we dive in, let's lock in what you're about to build and why it matters. This is your moment to commit to the problem you're solving and the approach you'll take.

Set Up Your Kaggle Notebook

Before you can train fraud detection models, you need a working environment with the dataset attached and all libraries ready to go.

In this step, you'll create a Kaggle Notebook, attach the Credit Card Fraud Detection dataset, and install the machine learning libraries you'll use throughout the project.

In this step, get ready to:
  • Create a new Kaggle Notebook with the fraud detection dataset attached.
  • Install imbalanced-learn and import all required libraries.
  • Load the dataset and confirm its shape.
Create a new Kaggle Notebook and attach the dataset

Kaggle Notebooks are free, browser-based Jupyter environments that come pre-loaded with common data science libraries. You'll create one from the dataset's page so the data is automatically available.

  • Go to kaggle.com and sign in to your account.
  • In the search bar at the top of the page, type Credit Card Fraud Detection and press Enter.
  • Select the dataset by Machine Learning Group - ULB (the dataset identifier is mlg-ulb/creditcardfraud).
  • On the dataset page, click New Notebook.
  • A new notebook opens in the editor with the dataset already attached.

You should see the notebook editor with a Settings pane on the right side. Expand the Input section in the Settings pane to confirm creditcardfraud appears as an attached data source.

Name your notebook

Click the notebook title in the top-left corner and rename it to something descriptive like fraud-detection-pipeline. This makes it easy to find later in your Kaggle profile.

Don't see the dataset attached?

If the Input section is empty, click Add Input in the Settings pane on the right. Search for Credit Card Fraud Detection and select the dataset by Machine Learning Group - ULB.

If you cannot see the Settings pane at all, look for a small arrow icon in the bottom-right corner of the screen and click it to reveal the panel.

Help me attach the Credit Card Fraud Detection dataset to my Kaggle Notebook

Install imbalanced-learn and import all libraries

Kaggle's environment includes most data science libraries, but imbalanced-learn is not guaranteed to be pre-installed. You'll install it first, then import everything you need for the project.

  • Delete any placeholder code in the first cell of your notebook.
  • Paste the following code into the first cell to install imbalanced-learn and import all required libraries:
# Cell 1: Setup and Imports
!pip install imbalanced-learn -q

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import IsolationForest, RandomForestClassifier
from sklearn.metrics import (
    classification_report,
    ConfusionMatrixDisplay,
    precision_recall_curve,
    average_precision_score
)
from imblearn.over_sampling import SMOTE
from imblearn.pipeline import Pipeline
  • Run the cell by pressing Shift+Enter.

What does this code do?

  • !pip install imbalanced-learn -q installs the imbalanced-learn library quietly (the -q flag suppresses most output).
  • pandas and numpy handle data manipulation and numerical operations.
  • matplotlib and seaborn create visualizations like confusion matrices and charts.
  • scikit-learn provides the machine learning models (IsolationForest, RandomForestClassifier) and evaluation metrics.
  • SMOTE from imbalanced-learn generates synthetic minority samples to address class imbalance.
  • Pipeline from imblearn.pipeline chains SMOTE with a classifier so resampling only happens during training, never during prediction.

You should see a brief pip output followed by no errors. If the cell finishes without a traceback, all imports succeeded.

Seeing an ImportError?

If you see an error about imblearn not being found, make sure the !pip install imbalanced-learn -q line is at the top of the cell and runs before the import statements.

If scikit-learn imports fail, check that you are using a Python notebook (not R). You can verify this in the Session options section of the Settings pane.

Help me fix my import errors in Kaggle

Load and verify the dataset

With libraries imported, you can now load the credit card transactions CSV and confirm it has the expected shape.

  • Click the + Code button to create a new cell below the imports.
  • Paste the following code into the new cell to load and inspect the dataset:
# Cell 2: Load Dataset
df = pd.read_csv('/kaggle/input/creditcardfraud/creditcard.csv')
print(f"Dataset shape: {df.shape}")
print(f"\nClass distribution:")
print(df['Class'].value_counts())
print(f"\nFraud percentage: {df['Class'].mean() * 100:.3f}%")
  • Run the cell by pressing Shift+Enter.

What does this code do?

  • pd.read_csv(...) loads the CSV file from the Kaggle dataset path into a pandas DataFrame called df.
  • df.shape prints the number of rows and columns so you can verify the full dataset loaded.
  • df['Class'].value_counts() shows how many transactions are legitimate (0) versus fraudulent (1).
  • The fraud percentage calculation reveals just how extreme the class imbalance is.

Before you check the output, what do you think the fraud percentage will be in a real-world dataset of nearly 285,000 transactions?

You should see the following output confirming the dataset loaded correctly:

  • Dataset shape: (284807, 31) confirms all 284,807 transactions and 31 columns loaded.
  • Class distribution shows 284,315 legitimate transactions (class 0) and 492 fraudulent ones (class 1).
  • Fraud percentage: 0.172% confirms the extreme imbalance. Only about 1 in 580 transactions is fraud.

Seeing a FileNotFoundError?

The path /kaggle/input/creditcardfraud/creditcard.csv only works when the dataset is attached to your notebook. Go back to the Input section in the Settings pane and confirm creditcardfraud is listed.

If you attached a different dataset by mistake, remove it and search for the one by Machine Learning Group - ULB with the identifier mlg-ulb/creditcardfraud.

Help me fix the FileNotFoundError for the credit card dataset

✔️ Awesome, I've got everything!

Great. Make sure your notebook is saved. Kaggle auto-saves periodically, but you can also press Ctrl+S (Windows) or Cmd+S (macOS) to save manually.

ⓧ I'd like to double check the full code

Here is everything your notebook should contain so far across both cells:

# Cell 1: Setup and Imports
!pip install imbalanced-learn -q

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import IsolationForest, RandomForestClassifier
from sklearn.metrics import (
    classification_report,
    ConfusionMatrixDisplay,
    precision_recall_curve,
    average_precision_score
)
from imblearn.over_sampling import SMOTE
from imblearn.pipeline import Pipeline

# Cell 2: Load Dataset
df = pd.read_csv('/kaggle/input/creditcardfraud/creditcard.csv')
print(f"Dataset shape: {df.shape}")
print(f"\nClass distribution:")
print(df['Class'].value_counts())
print(f"\nFraud percentage: {df['Class'].mean() * 100:.3f}%")

Your environment is ready and the data is loaded. Next up, you'll visualize just how extreme that 0.172% fraud rate looks in a chart and preprocess the features for modeling.

Explore the Imbalance and Preprocess

Your environment is ready and the dataset is loaded. Before you can build any model, you need to see the problem with your own eyes.

The fraud detection challenge lives and dies on one number: 0.172%. Only 492 out of 284,807 transactions are fraudulent. You need to see this imbalance visually before you can design an approach to handle it.

In this step, get ready to:
  • Visualize the extreme class imbalance with a bar chart and boxplot.
  • Scale raw features and split the data into training and test sets.
Visualize the class distribution and transaction amounts

Numbers like "0.172%" are easy to skim past. A chart makes the scale of the problem impossible to ignore.

  • Create a new code cell below Cell 2 and paste the following visualization code:
# Cell 3: Visualize the Imbalance
fig, axes = plt.subplots(1, 2, figsize=(12, 4))

sns.countplot(x='Class', data=df, ax=axes[0])
axes[0].set_title('Transaction Class Distribution')
axes[0].set_xticklabels(['Legitimate', 'Fraud'])

sns.boxplot(x='Class', y='Amount', data=df, ax=axes[1], showfliers=False)
axes[1].set_title('Transaction Amount by Class')
axes[1].set_xticklabels(['Legitimate', 'Fraud'])

plt.tight_layout()
plt.show()

What does this code do?

This creates two side-by-side plots using seaborn and matplotlib.

  • The left chart (sns.countplot) shows how many transactions fall into each class. The fraud bar will be barely visible.
  • The right chart (sns.boxplot) compares transaction amounts between legitimate and fraud classes, with extreme outliers hidden via showfliers=False.
  • Run the cell by pressing Shift+Enter.

You should see a bar chart where the legitimate bar towers over the fraud bar. The fraud bar is so small it looks like a thin line at the bottom of the chart. That is 492 transactions hiding among 284,315.

Don't see a chart?

  • Make sure you ran all previous cells first (Cell 1 and Cell 2). The chart depends on the df variable created in Cell 2.
  • Check that your cell contains plt.show() at the end. Without it, the plot may not render.

Why isn't my visualization showing in my Kaggle notebook?

Why does this imbalance matter?

A model that simply predicts "legitimate" for every single transaction would be 99.8% accurate. That sounds great, but it would miss every single fraud. This is why accuracy is a useless metric for imbalanced datasets.

You need metrics that specifically measure how well the model finds the rare fraud cases. That is what precision and recall are for, and you will use them in later steps.

Scale the non-PCA features and split data

The dataset's V1-V28 features are already PCA-transformed and scaled. The Amount and Time columns are not. You need to bring them to the same scale so they do not dominate the model.

  • Create a new code cell below Cell 3 and paste the following preprocessing code:
# Cell 4: Preprocessing
scaler = StandardScaler()
df['Scaled_Amount'] = scaler.fit_transform(df['Amount'].values.reshape(-1, 1))
df['Scaled_Time'] = scaler.fit_transform(df['Time'].values.reshape(-1, 1))
df = df.drop(['Amount', 'Time'], axis=1)

X = df.drop('Class', axis=1)
y = df['Class']

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

print(f"Training set: {X_train.shape[0]} samples")
print(f"Test set: {X_test.shape[0]} samples")
print(f"Fraud in test set: {y_test.sum()} ({y_test.mean()*100:.3f}%)")

What does this code do?

  • StandardScaler transforms Amount and Time to have zero mean and unit variance, matching the scale of the PCA features.
  • The original Amount and Time columns are dropped to avoid duplicate information.
  • stratify=y ensures the train/test split preserves the same 0.172% fraud ratio in both sets. Without it, you could end up with almost no fraud samples in the test set.

Before you run this cell, what do you think the fraud percentage in the test set will be? Will it match the original 0.172%, or will it be different?

  • Run the cell by pressing Shift+Enter.

You should see output confirming 227,845 training samples, 56,962 test samples, and a fraud percentage of 0.172% in the test set. That matches the original ratio exactly, thanks to the stratified split.

Seeing a KeyError for Amount or Time?

  • This means you ran Cell 4 more than once. The first run already dropped those columns. Click **Restart & Run All** from the **Run** menu at the top to reset from scratch.
  • Alternatively, re-run Cell 2 first to reload the raw DataFrame, then run Cell 3 and Cell 4 again.

Why am I getting a KeyError when running my preprocessing cell?

✔️ Awesome, I've got everything!

Great. Double check you have saved your notebook (Kaggle auto-saves, but you can press Ctrl+S or Cmd+S to be sure).

ⓧ I'd like to double check the full code

Scroll through your notebook and confirm you have these four cells in order:

  • Cell 1: Setup and Imports (the !pip install line plus all import statements).
  • Cell 2: Load Dataset (reads the CSV and prints shape, class distribution, fraud percentage).
  • Cell 3: Visualize the Imbalance (creates the side-by-side countplot and boxplot).
  • Cell 4: Preprocessing (scales Amount/Time, drops originals, splits into train/test with stratify=y).

You now have a clean, scaled dataset split into training and test sets that both preserve the original fraud ratio. Next up, you will train an IsolationForest anomaly detector and see whether an unsupervised approach can handle this extreme imbalance.

Build the IsolationForest Anomaly Detector

Your preprocessing is complete and you have a clean train/test split ready. Now it is time to build your first fraud detection model.

IsolationForest is an unsupervised anomaly detection algorithm that works without needing labeled data. It isolates anomalies by randomly partitioning the feature space, which sounds perfect for rare-event detection like fraud. Let's see how well it actually performs on our extremely imbalanced dataset.

In this step, get ready to:
  • Train an IsolationForest model on the transaction data.
  • Evaluate its fraud detection performance with a classification report.
  • Visualize the results with a confusion matrix.
Train IsolationForest and evaluate predictions

IsolationForest detects anomalies by randomly selecting a feature and then randomly selecting a split value. Anomalies are isolated in fewer splits because they are rare and different. The algorithm doesn't look at the Class column at all during training.

  • Create a new cell in your Kaggle Notebook and paste the following code:
# Cell 5: IsolationForest Anomaly Detection
iso_forest = IsolationForest(
    n_estimators=100,
    contamination=0.00172,
    random_state=42,
    n_jobs=-1
)

iso_forest.fit(X_train)

iso_preds = iso_forest.predict(X_test)
# IsolationForest: 1 = inlier, -1 = outlier
# Map to our labels: -1 -> 1 (fraud), 1 -> 0 (legitimate)
iso_preds_mapped = np.where(iso_preds == -1, 1, 0)

print("=== IsolationForest Results ===")
print(classification_report(y_test, iso_preds_mapped, target_names=['Legitimate', 'Fraud']))

What does this code do?

This cell trains and evaluates your anomaly detector in three stages:

  • contamination=0.00172 tells the model that 0.172% of transactions are expected to be anomalies. This matches the actual fraud rate in the dataset, giving IsolationForest its best shot.
  • iso_forest.predict() returns 1 for normal transactions and -1 for detected anomalies.
  • np.where() maps those outputs to match our dataset labels: -1 becomes 1 (fraud) and 1 becomes 0 (legitimate).

Before you run this cell, think about what you expect. IsolationForest has never seen the fraud labels. Do you think it will catch most fraud, miss most fraud, or produce many false alarms?

  • Run the cell by pressing Shift+Enter.

The classification report prints. Look at the Fraud row. You should see recall around 80-90% (it catches most fraud), but precision is very low. That low precision means hundreds of legitimate transactions are being flagged as fraud.

Why is precision so low?

IsolationForest never saw the labels during training. It only knows that some transactions look "different" from the majority. Many legitimate transactions also look unusual (large purchases, odd times), so the model flags them too.

This is the fundamental weakness of the unsupervised approach on this problem. High recall (catching fraud) comes at the cost of terrible precision (too many false alarms). You will fix this in the next step.

Seeing an error instead of the report?

  • Make sure you ran all previous cells first (Cells 1-4). The variables X_train and X_test must exist before this cell runs.
  • Check that the code is in a new cell, not appended to a previous cell.

Help me debug my IsolationForest cell

Plot the confusion matrix

The classification report gives numbers, but a confusion matrix makes the false positive problem impossible to ignore. It shows exactly how many legitimate transactions got incorrectly flagged.

  • Create a new cell below and paste this code:
# Cell 6: IsolationForest Confusion Matrix
fig, ax = plt.subplots(figsize=(6, 5))
ConfusionMatrixDisplay.from_predictions(
    y_test, iso_preds_mapped,
    display_labels=['Legitimate', 'Fraud'],
    ax=ax,
    cmap='Blues'
)
ax.set_title('IsolationForest Confusion Matrix')
plt.tight_layout()
plt.show()

What does this code do?

  • ConfusionMatrixDisplay.from_predictions() creates a grid showing correct vs. incorrect predictions for each class.
  • The top-left cell shows correctly identified legitimate transactions. The bottom-right shows correctly caught fraud.
  • The top-right cell is the problem: legitimate transactions the model incorrectly flagged as fraud (false positives).
  • Run the cell by pressing Shift+Enter.

The confusion matrix renders. Look at the top-right cell. You should see hundreds of legitimate transactions incorrectly flagged as fraud. That is the false positive problem in action.

Confusion matrix not displaying?

  • Verify that Cell 5 ran successfully before this cell. The variable iso_preds_mapped must exist.
  • If you see a blank output, check that plt.show() is included at the end of the cell.

Help me fix my confusion matrix display

✔️ Awesome, I've got everything!

Great. Confirm both Cell 5 and Cell 6 ran without errors and you can see the classification report output and the confusion matrix plot.

ⓧ I'd like to double check the full code

Your notebook should now have 6 cells in this order:

  • Cell 1: Setup and Imports (the !pip install and all import statements).
  • Cell 2: Load Dataset (pd.read_csv and shape/distribution prints).
  • Cell 3: Visualize the Imbalance (the two-panel countplot and boxplot).
  • Cell 4: Preprocessing (StandardScaler, feature drop, and train_test_split).
  • Cell 5: IsolationForest Anomaly Detection (model training, predictions, and classification report).
  • Cell 6: IsolationForest Confusion Matrix (the single-panel confusion matrix plot).

Scroll through your notebook and confirm each cell is present in this order. If any cell is missing, add it back from the code blocks above.

You have now seen the unsupervised approach in action. IsolationForest catches fraud, but it also raises far too many false alarms on legitimate transactions. Next up, you will build a supervised model that leverages the labeled data to dramatically cut down those false positives.

Build the SMOTE + Random Forest Pipeline

Your IsolationForest is trained and evaluated. The confusion matrix told a clear story: the model catches fraud, but it flags hundreds of legitimate transactions as suspicious.

The core issue is that IsolationForest ignores labels entirely. In this step, you will build a supervised pipeline that uses SMOTE to balance the training data, then trains a Random Forest that learns what fraud actually looks like.

In this step, get ready to:
  • Build an imblearn Pipeline that combines SMOTE oversampling with a Random Forest classifier.
  • Compare SMOTE + Random Forest results against IsolationForest using side-by-side confusion matrices.
Build and train the imblearn Pipeline

SMOTE creates synthetic examples of the minority class (fraud) so that the classifier trains on balanced data. The imblearn Pipeline ensures SMOTE only runs during training, never during prediction.

  • Create a new code cell in your Kaggle Notebook and paste the following code to build, train, and evaluate the pipeline:
smote_rf_pipeline = Pipeline([
    ('smote', SMOTE(random_state=42)),
    ('classifier', RandomForestClassifier(
        n_estimators=100,
        random_state=42,
        n_jobs=-1
    ))
])

smote_rf_pipeline.fit(X_train, y_train)

rf_preds = smote_rf_pipeline.predict(X_test)

print("=== SMOTE + Random Forest Results ===")
print(classification_report(y_test, rf_preds, target_names=['Legitimate', 'Fraud']))

What does this code do?

  • Pipeline from imblearn chains two steps: first SMOTE resamples the training data to create synthetic fraud examples, then RandomForestClassifier trains on the now-balanced dataset.
  • When you call .predict(X_test), SMOTE is skipped automatically. Resampling only happens during .fit(), which prevents data leakage into your test set.
  • n_jobs=-1 uses all available CPU cores for faster training.

Why imblearn Pipeline instead of sklearn Pipeline?

Scikit-learn's built-in Pipeline does not support samplers like SMOTE. It only handles transformers (fit/transform) and a final estimator (fit/predict).

The imblearn Pipeline extends sklearn's version to handle resamplers during fit. This is why you imported from imblearn.pipeline import Pipeline in Cell 1.

Before you run this cell, what do you think will happen to the false positive count compared to IsolationForest?

  • Run the cell.

The classification report shows fraud precision and recall both above 80%. Compare that to IsolationForest's low precision from the previous step. The supervised model dramatically reduces false positives because it learned what fraud looks like from labeled examples.

Seeing a NameError or import error?

  • Make sure you ran Cell 1 (imports) and Cell 4 (preprocessing) earlier in this session. Kaggle resets variables if the kernel restarts.
  • Confirm your import line says from imblearn.pipeline import Pipeline, not from sklearn.pipeline import Pipeline.

Help me fix my SMOTE + Random Forest pipeline error

Compare models with side-by-side confusion matrices

Numbers in a classification report are useful, but a visual comparison makes the improvement unmistakable. Placing both confusion matrices next to each other reveals the false positive gap at a glance.

  • Create a new code cell and paste the following to render both confusion matrices side by side:
fig, axes = plt.subplots(1, 2, figsize=(12, 5))

ConfusionMatrixDisplay.from_predictions(
    y_test, iso_preds_mapped,
    display_labels=['Legitimate', 'Fraud'],
    ax=axes[0],
    cmap='Blues'
)
axes[0].set_title('IsolationForest (Unsupervised)')

ConfusionMatrixDisplay.from_predictions(
    y_test, rf_preds,
    display_labels=['Legitimate', 'Fraud'],
    ax=axes[1],
    cmap='Blues'
)
axes[1].set_title('SMOTE + Random Forest (Supervised)')

plt.tight_layout()
plt.show()

What does this code do?

  • plt.subplots(1, 2) creates a figure with two side-by-side plots so you can compare both models in one view.
  • ConfusionMatrixDisplay.from_predictions generates each matrix directly from true labels and predictions. The left plot uses IsolationForest results, the right uses SMOTE + Random Forest.
  • The top-right cell (Legitimate predicted as Fraud) is the false positive count. A smaller number there means fewer innocent transactions flagged.
  • Run the cell.

You should see two confusion matrices side by side. The right matrix (SMOTE + Random Forest) has dramatically fewer false positives in the top-right cell compared to the left matrix (IsolationForest).

Both matrices look the same?

  • Check that the left plot uses iso_preds_mapped and the right plot uses rf_preds. Swapping them shows the same model twice.
  • Make sure Cell 7 (the pipeline cell) ran successfully before this cell. If rf_preds was not created, you will see an error instead.

Help me debug my side-by-side confusion matrices

✔️ Awesome, I've got everything!

Great. Make sure both Cell 7 and Cell 8 are saved in your notebook.

ⓧ I'd like to double check the full code

Scroll up through your notebook and confirm these cells exist in order:

  • Cell 7: Defines the imblearn Pipeline with SMOTE and RandomForestClassifier, fits on training data, predicts on test data, and prints the classification report.
  • Cell 8: Plots two confusion matrices side by side comparing IsolationForest (left) and SMOTE + Random Forest (right).

Your supervised pipeline crushes the unsupervised approach on this labeled dataset. Next up, you will evaluate both models using Precision-Recall curves and map this entire pattern to IoT sensor anomaly detection.

Evaluate with Precision-Recall Curves and Map to IoT

Your side-by-side confusion matrices from the previous step made the verdict clear. SMOTE + Random Forest dramatically outperforms IsolationForest at separating fraud from legitimate transactions.

But there is a deeper problem with evaluating models on this dataset. At 99.8% class imbalance, a model that predicts "legitimate" for every single transaction achieves 99.8% accuracy. Precision-Recall curves reveal the true performance trade-off across all possible decision thresholds, making them the correct evaluation tool here.

In this step, get ready to:
  • Plot Precision-Recall curves with AUPRC scores for both models.
  • Confirm visually that SMOTE + Random Forest dominates IsolationForest.
  • Map the dual-model fraud detection pattern to IoT sensor anomaly detection.
Plot Precision-Recall curves with AUPRC scores

The original dataset description itself recommends AUPRC (Area Under the Precision-Recall Curve) as the correct metric for this data. A single number summarizes how well each model balances precision and recall across every possible threshold.

Before you run this next cell, think: which model do you expect to have a higher AUPRC score, and why?

  • Create a new cell below your side-by-side confusion matrices and paste the following code to compute probability scores and plot Precision-Recall curves for both models:
rf_probs = smote_rf_pipeline.predict_proba(X_test)[:, 1]
iso_scores = -iso_forest.decision_function(X_test)

rf_precision, rf_recall, _ = precision_recall_curve(y_test, rf_probs)
iso_precision, iso_recall, _ = precision_recall_curve(y_test, iso_scores)

rf_ap = average_precision_score(y_test, rf_probs)
iso_ap = average_precision_score(y_test, iso_scores)

fig, ax = plt.subplots(figsize=(8, 6))
ax.plot(rf_recall, rf_precision, label=f'SMOTE + RF (AUPRC = {rf_ap:.3f})')
ax.plot(iso_recall, iso_precision, label=f'IsolationForest (AUPRC = {iso_ap:.3f})')
ax.set_xlabel('Recall')
ax.set_ylabel('Precision')
ax.set_title('Precision-Recall Curve Comparison')
ax.legend()
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

What does this code do?

This cell extracts continuous scores from both models and uses them to plot how precision and recall trade off at every possible threshold.

  • predict_proba(X_test)[:, 1] gets the Random Forest's fraud probability for each transaction (a value between 0 and 1).
  • -iso_forest.decision_function(X_test) gets the IsolationForest's anomaly scores. The negative sign flips them so that higher values mean "more likely fraud."
  • average_precision_score computes the AUPRC. A perfect model scores 1.0. A random model on this dataset scores around 0.002 (the fraud rate).
  • Run the cell.

You should see a plot with two curves. The SMOTE + RF curve hugs the top-right corner (high precision AND high recall), while the IsolationForest curve drops much faster. The legend shows AUPRC scores confirming the supervised model dominates.

Why not just use accuracy?

A model that always predicts "legitimate" gets 99.83% accuracy on this dataset. That tells you nothing about its ability to catch fraud. AUPRC isolates exactly what you care about: how well the model finds the rare positive class.

This is why the dataset creators explicitly state that AUPRC is the recommended metric for this problem.

Not seeing the plot?

  • Make sure you ran all previous cells in order. The cell depends on smote_rf_pipeline, iso_forest, X_test, and y_test all being defined.
  • If you see a NameError, click **Restart & Run All** from the **Run** menu to re-execute the notebook from the top.
  • help me debug my Precision-Recall curve cell in Kaggle
Map the pattern to IoT sensor monitoring

The dual-model approach you just built is not specific to credit card fraud. The same pattern applies anywhere you face extreme class imbalance with rare events. IoT sensor monitoring is one of the most common real-world parallels.

  • Create a new cell below your Precision-Recall plot and paste the following code to print the domain mapping table:
print("""
=== Mapping to IoT Sensor Anomaly Detection ===

The dual-model pattern you built transfers directly to IoT:

| Credit Card Fraud              | IoT Sensor Monitoring          |
|--------------------------------|--------------------------------|
| Transaction features (V1-V28) | Sensor readings (temp, vibration, pressure) |
| Class: Fraud/Legitimate        | Label: Anomaly/Normal          |
| 0.172% fraud rate              | Rare equipment failures        |
| IsolationForest                | Detect unknown failure modes   |
| SMOTE + Classifier             | Detect known failure patterns  |
| Precision: avoid false alarms  | Avoid unnecessary shutdowns    |
| Recall: catch all fraud        | Catch all real failures        |

Key Insight: In both domains, you face extreme class imbalance.
- IsolationForest works WITHOUT labels (deploy when you have sensor data but no failure history)
- SMOTE + Classifier works WITH labels (deploy once you accumulate labeled failure events)
- In production, deploy BOTH: the classifier catches known patterns,
  the anomaly detector flags novel/unseen failure modes.
""")

Why does this mapping matter?

The table makes explicit which concept from fraud detection maps to which concept in IoT monitoring. The key insight is about when to deploy each model type.

  • IsolationForest (unsupervised) is useful when you have NO labeled failure history. It detects anything that looks "unusual" without needing examples of what a failure looks like.
  • SMOTE + Classifier (supervised) is useful AFTER you accumulate labeled events. It leverages those labels to dramatically reduce false alarms.
  • Production systems deploy both: the classifier catches known patterns, and the anomaly detector flags novel failure modes nobody has seen before.
  • Run the cell.

You should see the mapping table printed clearly in the cell output, showing each fraud detection concept alongside its IoT equivalent.

Seeing a syntax error?

  • Triple-quoted strings are sensitive to indentation. Make sure the opening print(""" and closing """) are on their own lines with no extra spaces.
  • help me fix a syntax error in my print statement

✔️ Awesome, I've got everything!

Great. Make sure both Cell 9 and Cell 10 ran without errors and you can see the Precision-Recall plot and the IoT mapping table in your notebook output.

ⓧ I'd like to double check the full code

Scroll up through your notebook and confirm you have these cells in order:

  • Cell 1: Setup and Imports (!pip install and all import statements).
  • Cell 2: Load Dataset (pd.read_csv and print statements).
  • Cell 3: Visualize the Imbalance (bar chart and box plot).
  • Cell 4: Preprocessing (StandardScaler, drop columns, train/test split).
  • Cell 5: IsolationForest Anomaly Detection (train and predict).
  • Cell 6: IsolationForest Confusion Matrix.
  • Cell 7: SMOTE + Random Forest Pipeline (train and predict).
  • Cell 8: Side-by-Side Confusion Matrices.
  • Cell 9: Precision-Recall Curve Comparison (rf_probs, iso_scores, AUPRC scores, and plot).
  • Cell 10: IoT Sensor Anomaly Detection Mapping (print table).

You now have a complete evaluation proving SMOTE + Random Forest dominates IsolationForest on this problem. You also have a conceptual framework showing how this exact pipeline transfers to IoT sensor monitoring. Next up, tackle the Secret Mission to fine-tune the classification threshold for a specific business target.

Secret mission

Threshold Tuning for Business Constraints

Your Random Forest model uses 0.5 as the default classification threshold. But real fraud detection systems don't use arbitrary defaults. In this secret mission, you'll tune the threshold to hit a specific business target: catch at least 95% of all fraud, then measure the cost in false positives.

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely on Kaggle Notebooks with a public dataset, so there are no ongoing costs.

Resources you used:

  • Kaggle Notebook (your fraud detection notebook saved in your Kaggle account).
  • Attached dataset (Credit Card Fraud Detection by Machine Learning Group - ULB).

Keep everything running

No action needed. Choose this if you want to revisit or extend the notebook later.

  • Your notebook remains saved in your Kaggle account indefinitely at no cost.
  • The attached dataset is public and does not consume any storage quota.
  • You can return to your notebook anytime from your Kaggle profile.

Pause - I'll come back to this later

Since Kaggle Notebooks are free and stored indefinitely, pausing simply means stopping the active session.

  • Click the power button icon at the top right of the notebook editor to stop the active session.
  • Your notebook code and outputs remain saved automatically.
  • When you return, click the play button on a cell to restart the session.

Delete - I don't want to use this again

Remove the notebook from your Kaggle profile entirely.

  • Open your Kaggle profile by clicking your avatar in the top right corner, then selecting your profile.
  • Navigate to the Code tab to see your saved notebooks.
  • Click the three-dot menu on your fraud detection notebook.
  • Select Delete and confirm the deletion.
  • The attached dataset is public and belongs to the dataset owner. Removing your notebook does not affect the dataset.

Nice Work!

Nice Work!

Nice work! You just built a dual-model fraud detection system that processes 284,807 real credit card transactions and proves why supervised learning with SMOTE dominates unsupervised anomaly detection on extremely imbalanced data.

You've learned how to:

  • Built an IsolationForest anomaly detector and discovered its false-positive weakness on data where only 0.172% of transactions are fraudulent.
  • Constructed an imblearn Pipeline combining SMOTE oversampling with Random Forest classification that dramatically outperforms the unsupervised approach on precision, recall, and AUPRC.
  • Mapped the dual-model fraud detection pattern to IoT sensor anomaly detection, understanding when to deploy unsupervised models (no failure history) versus supervised models (labeled failure events).
  • Secret Mission: Tuned the classification threshold to meet a specific business recall target of 95%, understanding the precision/recall trade-off in practice.

Ready to quiz yourself?