PayKart processes card payments for online shops. Some payments are made with stolen cards. If a risky payment goes through, PayKart pays the money back to the real card owner.
The risk team has 600 recent transactions, already checked by investigators and marked risky or not. They want a model that flags a new payment as risky before it goes through, so it can ask for an extra OTP.
Goal: Predict risky (Yes / No) for a new payment. A Support Vector Machine draws the widest possible boundary between the two groups, and with a kernel it can draw curved boundaries too.
600 transactions, one row each.
| txn_id | amount_k | hour | distance_from_home_km | new_device | txns_last_hour | risky |
|---|---|---|---|---|---|---|
| 20001 | 1.1 | 7 | 2.2 | No | 0 | No |
| 20002 | 7.2 | 0 | 7.4 | No | 0 | No |
| 20003 | 12.0 | 17 | 2.4 | No | 0 | No |
| 20004 | 9.0 | 17 | 5.8 | No | 0 | No |
| 20005 | 6.5 | 13 | 3.4 | No | 0 | No |
| 20006 | 1.6 | 22 | 139.6 | No | 0 | Yes |
First 6 of 600 rows · realistic practice data
Press Run on each step in order, or run them all at once. You can change any code and run it again.
Starting Python…
Look at the data and how many payments were risky. Risky payments are the minority, which is normal in fraud data.
Amount and distance are skewed: most payments are small and close, a few are huge and far. Those few would dominate the distances an SVM uses. Taking the log squeezes the big values together. We use log1p (log of 1 + x) so that 0 stays 0.
SVMs measure distances, so scaling is a must. A pipeline keeps scaling and the model together.
A linear SVM finds the straight boundary with the widest margin: the biggest empty gap between the two groups. Only the points closest to the gap (the support vectors) decide where it goes. We look at recall, the share of risky payments caught, because a missed fraud costs real money. Watch out: if recall is 0, the model never flags anything, even when the accuracy looks high.
Fraud is not always on one side of a line. For example, a payment at 3 am is risky, and so is one at 11 pm, but 2 pm is normal. The RBF kernel lets the SVM draw curved boundaries. class_weight="balanced" tells it that missing a rare risky payment matters more.
Two settings control the RBF SVM:
GridSearchCV tries every pair with cross-validation and keeps the best. We judge by F1, which balances recall and precision: judging by recall alone would reward a model that flags every payment.
The confusion matrix of the tuned model. Normal payments flagged as risky only cost an extra OTP; risky payments that slip through cost money.
A ₹45,000 payment at 2 am, 1,200 km from home, from a new phone, with 3 other payments in the last hour. Change the values and run again. New data must get the same log steps as the training data.
20 questions on new data. You write the code; hints point the way without giving it.