I Built a BFIU-Compliant AML Detection System in Python (Here's Why the Kaggle Approach Doesn't Work

I Built a BFIU-Compliant AML Detection System in Python (Here's Why the Kaggle Approach Doesn't Work)

Most AML tutorials end with a confusion matrix and a 99% accuracy score. Here's why that doesn't work — and what I built instead. I've been working in fintech compliance data for a while. The one thing I kept noticing: every "fraud detection project" on GitHub or Kaggle uses the same dataset — the UCI credit card fraud dataset from 2013. It has 284,000 rows, 30 features labeled V1-V28, and approximately zero explanatory value for anyone who wants to understand how financial crime actually works. So I built something different. The problem with the standard approach Real transaction monitoring engines don't work like Kaggle competitions. They don't take a CSV, train a model, and output a probability score. They work like this: A rule engine runs first — deterministic, auditable, regulatory-cited rules that generate alerts Those alerts get scored and triaged by risk tier An ML layer reduces false positives among the high-risk alerts ...

How I Uncovered the Dark Side of AML Models: The Urgent Need for Explainability

explainable-ai

Photo by Juno Jo on Unsplash

I still remember the day our AML system flagged over 10,000 transactions as suspicious, only to find out that 90% of them were false positives. The regulator was breathing down our necks, and our team was under immense pressure to explain each and every one of those flags. That's when I realized the harsh truth: our AML models, despite being highly accurate on paper, were black boxes that nobody could interpret.

The Hidden Problem

In Bangladesh, where the BFIU guidelines are strict and the MFS threshold monitoring is a challenge, AML models need to be more than just accurate. They need to be explainable. But standard approaches often fall short. I've seen it time and time again: a model is trained on a dataset, it performs well on the test set, and then it's deployed. But when it comes to explaining why a particular transaction was flagged, the model falls silent.

Technical Breakdown & Logic Flow

To tackle this problem, I decided to take a step back and re-evaluate our approach. I started by breaking down the transaction data into smaller, more manageable chunks. I looked at the transaction amount, the sender and recipient information, and the timing of the transaction. I then used a combination of rule-based systems and machine learning algorithms to identify patterns and anomalies.

The logic flow was as follows: first, the system would check if the transaction amount exceeded the BDT 100,000 threshold. If it did, the system would then check the sender and recipient information to see if it matched any known PEP lists. If it did, the system would flag the transaction for further review. But here's the thing: the system wasn't just relying on rules. It was also using machine learning algorithms to identify patterns in the data that might not be immediately apparent.

For example, the system might identify a pattern where a particular sender was consistently sending large amounts of money to a particular recipient. Or it might identify a pattern where a particular recipient was consistently receiving large amounts of money from multiple senders. These patterns could indicate money laundering or terrorist financing, and the system would flag them for further review.

Python Implementation

import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split

# Load the transaction data
transactions = pd.read_csv('transactions.csv')

# Define the features and target variable
X = transactions[['transaction_amount', 'sender_info', 'recipient_info']]
y = transactions['flagged']

# Split the data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Train a random forest classifier on the training data
clf = RandomForestClassifier(n_estimators=100, random_state=42)
clf.fit(X_train, y_train)

# Use the trained model to predict the target variable for the testing data
y_pred = clf.predict(X_test)

The code above shows how I used a random forest classifier to predict the target variable for the testing data. But here's the thing: this is just one part of the solution. The real challenge is in explaining why the model made a particular prediction.

Local Application

In Bangladesh, the BFIU guidelines require that all suspicious transactions be reported to the authorities. But the guidelines also require that the reports be accompanied by a clear explanation of why the transaction was flagged. This is where the explainability of the model comes in.

I worked with our development team to integrate the explainability module into our AML system. The module uses a combination of feature importance and partial dependence plots to explain why a particular transaction was flagged. For example, the module might show that the transaction amount was the most important feature in determining whether a transaction was suspicious. Or it might show that the sender and recipient information were also important factors.

Common Pitfalls & Edge Cases

One of the common pitfalls I've seen is that the model can be over-reliant on a particular feature. For example, if the model is trained on a dataset where the transaction amount is the most important feature, it might start to flag all transactions with large amounts as suspicious. But this can lead to a high number of false positives, which can be frustrating for our customers and our compliance team.

To avoid this, I made sure to regularly review and update the model. I also made sure to test the model on a diverse range of scenarios, including edge cases where the transaction amount is large but the sender and recipient information is legitimate.

Counterintuitive Insight

One of the counterintuitive insights I've gained from working on this project is that explainability is not just about explaining why a model made a particular prediction. It's also about explaining why the model didn't make a particular prediction. For example, if a transaction is not flagged as suspicious, the model should be able to explain why it didn't flag it. This might seem obvious, but it's actually a really challenging problem.

I've seen cases where the model didn't flag a transaction as suspicious, but upon further review, it turned out that the transaction was actually suspicious. In these cases, the model should be able to explain why it didn't flag the transaction, so that we can improve the model and prevent similar mistakes in the future.

Conclusion & CTA

In conclusion, explainable AI is not just a nice-to-have in AML models. It's a must-have. Regulators demand it, and customers expect it. By providing clear explanations for why a particular transaction was flagged, we can build trust with our customers and our regulators. We can also improve the accuracy of our models and reduce the number of false positives.

So what can you do to apply these principles in your own work? First, start by reviewing your current AML models and asking yourself if they are explainable. If they're not, consider integrating an explainability module into your system. Second, make sure to regularly review and update your models to ensure that they are accurate and reliable. Finally, test your models on a diverse range of scenarios to ensure that they are robust and effective.

What's the most challenging part of implementing explainable AI in your AML models? Share your experiences in the comments below, and let's work together to build more transparent and trustworthy AML systems.

Comments

Popular posts from this blog

How to Use Notion to Improve Your Blog: A Step-by-Step Guide 🌱

Top 5 AI SEO Strategies to Skyrocket Your Blog Traffic in 2026 🚀

How to Start Freelancing with AI in 2025 for Beginners