Mctaba Labs logo
BootcampThe WhiteboardProjectsEventsMasterclassesWebinarsLearn
Book CallApply

500+ developers already in the community

Get answers, find accountability partners, and stay ahead

Join Discord →
Mctaba Labs logo

Educating 1 million students in tech by 2030.

Programs

  • Coding Bootcamp in Nairobi
  • Software Engineering Bootcamp
  • Data Science to AI Engineering
  • HighSchool Graduates Launchpad
  • AI & Business Automation
  • Corporate Training
  • Kids & Teens
  • McTaba Story & Mission
  • Full-Stack Curriculum
  • Course Pricing & Plans
  • Frequently Asked Questions

Resources

  • Join Discord Community
  • Tech Events in Nairobi
  • Masterclasses
  • Free Resources
  • Learn
  • Data Science Guides
  • African Payments Reference
  • Campus
  • Africa Tech Talent Report
  • Partner With Us
  • Start a Project
  • Software & AI Studio
  • Our Work
  • Outcomes

Contact Us

  • 124 Manyani East Road, Lavington, Nairobi
  • +254727795603
  • Book a Discovery Call

Office Hours:

Mon-Fri: 9am - 2pm EAT

Sat: 10am - 12pm EAT

© 2026 Mctaba Labs - A product of Edtech Industries. All rights reserved.

Privacy PolicyTerms of ServiceRefund Policy
  1. Learn
  2. Data Science in Kenya
  3. Catching Mobile Money Fraud with Machine Learning
Bonaventure OgetoBy Bonaventure Ogeto|Updated November 3, 2026

Last checked 3 November 2026

Catching Mobile Money Fraud with Machine Learning

Use the public PaySim dataset, keep only TRANSFER and CASH_OUT rows, skip the leaky after-balance columns, split by time and train a gradient boosting model with class weights. Then choose a score threshold by adding up the shillings missed and the cost of false alarms.

In this article

  1. 1. The data: PaySim, a simulated mobile money month
  2. 2. Class imbalance and the leak to avoid
  3. 3. Precision and recall in shillings
  4. 4. What a real system adds

The data: PaySim, a simulated mobile money month

McTaba runs coding and data bootcamps in Kenya. This guide is written to be useful whether or not you ever join one.

Real M-Pesa fraud data is private, and rightly so. The public stand-in is PaySim: a simulator, built from logs of a mobile money service, that produces transactions with fraud added. You can download it from the PaySim page on Kaggle (checked on 3 November 2026; a free Kaggle account is needed to download). The authors describe the simulator in a 2016 paper, "PaySim: A financial mobile money simulator for fraud detection", by Lopez-Rojas, Elmir and Axelsson.

This is one of the projects on our data science career map. M-Pesa fraud detection is also a capstone option in our Data Science to AI Engineering programme.

Each row has a step (one hour of the simulated month), a type, an amount, origin and destination balances, and an isFraud label. The data is synthetic, so any score you get here says nothing about real M-Pesa. It teaches the method.

StepWhy it matters
Check how rare fraud isRare labels make accuracy useless
Keep TRANSFER and CASH_OUTThe fraud pattern is takeover, move, cash out
Drop the after-balancesThey leak the answer
Split by timeTomorrow's fraud must be tested on yesterday's training

We teach metrics for imbalanced fraud data in phase 4 of the Data Science to AI Engineering programme.

Class imbalance and the leak to avoid

Print the share of fraud first. It is a tiny fraction of rows. A model that says "not fraud" every time would score above 99 percent accuracy and catch nothing. That is why we ignore accuracy here.

Read the dataset notes on Kaggle. They explain that fraud transactions are cancelled, so the balance columns after the transaction can give the answer away. Use only what a system knows before it approves the payment.

import pandas as pd
from sklearn.ensemble import HistGradientBoostingClassifier

df = pd.read_csv("PS_20174392719_1491204439457_log.csv")
print(df["isFraud"].mean())

df = df[df["type"].isin(["TRANSFER", "CASH_OUT"])].copy()
df["hour"] = df["step"] % 24
df["is_transfer"] = (df["type"] == "TRANSFER").astype(int)
df["pct_of_balance"] = df["amount"] / (df["oldbalanceOrg"] + 1)
cols = ["amount", "hour", "is_transfer",
        "oldbalanceOrg", "pct_of_balance"]

train, test = df[df["step"] <= 600], df[df["step"] > 600]
model = HistGradientBoostingClassifier(
    class_weight="balanced", random_state=0)
model.fit(train[cols], train["isFraud"])
p = model.predict_proba(test[cols])[:, 1]

The file name may differ on your download, so check it. class_weight="balanced" makes each rare fraud row count for more during training. The time split trains on the first 600 hours and tests on the rest. The feature pct_of_balance says what share of the account the payment drains: takeovers tend to empty it.

Get weekly developer tips

Join 25,000+ developers. Practical guides, job tips, and new content — straight to your inbox.

No spam. Unsubscribe anytime.

Precision and recall in shillings

Precision asks: of the payments we blocked, how many were fraud? Recall asks: of all the fraud, how much did we catch? Both are counts. A fraud team thinks in shillings, so convert.

Imagine each wrongly blocked payment costs KES 100 in staff time and an angry call. A missed fraud costs the full amount. The code adds both for four thresholds.

FALSE_ALARM = 100   # an assumption: change it to your own
fraud = test["isFraud"] == 1
rows = []
for t in [0.5, 0.8, 0.95, 0.99]:
    flag = p >= t
    missed = test.loc[~flag & fraud, "amount"].sum()
    alarms = int((flag & ~fraud).sum())
    rows.append({
        "threshold": t,
        "precision": (flag & fraud).sum() / max(flag.sum(), 1),
        "recall": (flag & fraud).sum() / fraud.sum(),
        "kes_missed": round(missed),
        "false_alarms": alarms,
        "total_cost": round(missed + alarms * FALSE_ALARM),
    })
print(pd.DataFrame(rows).round(3))

Read the table from the top. A low threshold blocks more, so recall rises and false alarms rise too. A high threshold is quiet but lets large frauds through. Pick the row with the lowest total cost, then ask whether the alarms it makes are a number your team can actually review in a day.

Now imagine you raise the alarm cost to KES 10,000. Run it again. The cheapest row moves, because each false alarm now hurts more than a missed small fraud. Always show the cost line with the threshold.

What a real system adds

  • Features about the sender's history: how many transfers in the last hour, a new device or SIM swap, a first-time recipient.
  • A review queue, not an auto-block, for the middle of the score range.
  • Monitoring, because fraudsters change their pattern when you catch them.

For signals taken from a card and wallet gateway, see fraud detection signals on payment data. For another scored-people project, read how to build a chama credit score. To serve the model to other systems, follow deploying a machine learning model with FastAPI. If you want to practise on other public data, see Kenyan open datasets.

Want to build this with mentors and show it at a demo day? See the Data Science to AI Engineering programme: 5 months full time or 8 months part time, KES 140,000, or KES 120,000 if paid in full upfront, next intake 11 January 2027.

Key Takeaways

  • ✓PaySim is a safe, public practice set. Its scores say nothing about real M-Pesa.
  • ✓Drop columns that only exist after the answer is known, and split by time.
  • ✓Judge a fraud model in shillings missed and alarms raised, not accuracy.
  • ✓A threshold is a business choice. Show its cost next to it.

Frequently Asked Questions

What is the PaySim dataset?
A public synthetic mobile money dataset on Kaggle, generated by a simulator built from real service logs. It has transaction types, amounts, balances and a fraud label.
Why not use accuracy for fraud detection?
Fraud is rare, so a model that flags nothing still looks very accurate. Use precision, recall and the shillings behind them.
How do I choose the threshold?
Score each candidate threshold by shillings missed plus the cost of false alarms, then check that your team can review the alarms it produces.
Will this work on real M-Pesa data?
The method carries over, the numbers do not. PaySim is simulated, so real data needs its own features, testing and monitoring.

Learn data science on African data

KES 140,000 (KES 120,000 upfront)

Data Science to AI Engineering: 5 months full time or 8 months part time, hybrid in Nairobi. Fraud, credit and M-Pesa data from Week 1, and every model deployed. Starts 11 January 2027.

See the Data Science programme

Need it live by next month? Our studio builds it

Related guides

  • AI vs Machine Learning vs Data Science: The Difference
  • Analyse Your M-Pesa Statement in Python
  • Forecast a Shop's Stock from Till Data

Keep reading

Build a Credit Score for a Chama from Contribution Records

Score members of a chama from their contribution history: first with points anyone can read, then with logistic regression, and with consent in mind.

Read more

Deploy a Machine Learning Model as an API with FastAPI

From a trained model file to a working API: save, serve, test with curl and put it in a Docker container, in four short steps.

Read more

Kenyan Open Datasets: Where to Find Real Data to Practise On

Where to find real Kenyan data for practice projects: eight sources, what each holds, the file format and the date we opened it.

Read more

Kaggle for Beginners: Your First Competition

A plain walk through your first Kaggle entry: account, notebook, baseline model, submission file and the habits that make the second try better.

Read more

Explore related topics

Breaking Into Tech

Practical, no-nonsense guides for anyone looking to start or change their career in tech. From choosing your first language to acing interviews.

Tech Salary Data

Transparent salary data for tech roles in Africa and worldwide, updated regularly with real market research.

AI Skills & Tools

Practical AI knowledge for developers. Build your first agent, get good at RAG, and pick the right AI coding tools for real work.

Bonaventure Ogeto

Bonaventure Ogeto

Founder and CEO, Mctaba Labs

Software engineer for 8+ years. He runs a Nairobi studio that ships products on M-Pesa, WhatsApp and AI, and teaches what the studio ships. He holds a BSc in Mathematics and Computer Science.

More about the author