Summary
datasets are extraordinarily imbalanced, with optimistic charges under 0.2%. Commonplace neural networks skilled with weighted binary cross-entropy usually obtain excessive ROC-AUC however wrestle to establish suspicious transactions below threshold-sensitive metrics. I suggest a Hybrid Neuro-Symbolic (HNS) strategy that comes with area data straight into the coaching goal as a differentiable rule loss — encouraging the mannequin to assign excessive fraud likelihood to transactions with unusually massive quantities and atypical PCA signatures. On the Kaggle Credit score Card Fraud dataset, the hybrid achieves ROC-AUC of 0.970 ± 0.005 throughout 5 random seeds, in comparison with 0.967 ± 0.003 for the pure neural baseline below symmetric analysis. A key sensible discovering: on imbalanced knowledge, threshold choice technique impacts F1 as a lot as mannequin structure — each fashions have to be evaluated with the identical strategy for any comparability to be significant. Code and reproducibility supplies can be found at GitHub.
The Drawback: When ROC-AUC Lies
I had a fraud dataset at 0.17% optimistic charge. Educated a weighted BCE community, bought ROC-AUC of 0.96, somebody mentioned “good”. Then I pulled up the rating distributions and threshold-dependent metrics. The mannequin had quietly discovered that predicting “not fraud” on something ambiguous was the trail of least resistance — and nothing within the loss operate disagreed with that call.
What bothered me wasn’t the maths. It was that the mannequin had no thought what fraud seems to be like. A junior analyst on day one might inform you: massive transactions are suspicious, transactions with uncommon PCA signatures are suspicious, and when each occur collectively, it is best to positively be paying consideration. That data simply… by no means makes it into the coaching loop.So I ran an experiment. What if I encoded that analyst instinct as a tender constraint straight within the loss operate — one thing the community has to fulfill whereas additionally becoming the labels? The end result was a Hybrid Neuro-Symbolic (HNS) setup. This text walks by the complete experiment: the mannequin, the rule loss, the lambda sweep, and — critically — what a correct multi-seed variance evaluation with symmetric threshold analysis truly reveals.
The Setup
I used the Kaggle Credit score Card Fraud dataset — 284,807 transactions, 492 of that are fraud (0.172%). The V1–V28 options are PCA parts from an anonymized unique characteristic area. Quantity and Time are uncooked. The extreme imbalance is the entire level; that is the place commonplace approaches begin to wrestle [1].
Break up was 70/15/15 practice/val/take a look at, stratified. I skilled 4 issues and in contrast them head-to-head:
- Isolation Forest — contamination=0.001, suits on the complete coaching set
- One-Class SVM — nu=0.001, suits solely on the non-fraud coaching samples
- Pure Neural — three-layer MLP with BCE + class weighting, no area data
- Hybrid Neuro-Symbolic — the identical MLP, with a differentiable rule penalty added to the loss
Isolation Forest and One-Class SVM function a gut-check. If a supervised community with 199k coaching samples can’t clear the bar set by an unsupervised technique, that’s price understanding earlier than you write up outcomes. A tuned gradient boosting mannequin would probably outperform each neural approaches; this comparability is meant to isolate the impact of the rule loss, not benchmark in opposition to all potential strategies. Full code for all 4 is on GitHub.
The Mannequin
Nothing unique. A 3-layer MLP with batch normalization after every hidden layer. The batch norm issues greater than you may anticipate — below heavy class imbalance, activations can drift badly with out it [3].
class MLP(nn.Module):
def __init__(self, input_dim):
tremendous().__init__()
self.web = nn.Sequential(
nn.Linear(input_dim, 128),
nn.ReLU(),
nn.BatchNorm1d(128),
nn.Linear(128, 64),
nn.ReLU(),
nn.BatchNorm1d(64),
nn.Linear(64, 1)
)
def ahead(self, x):
return self.web(x)
For the loss, BCEWithLogitsLoss with pos_weight — computed because the ratio of non-fraud to fraud counts within the coaching set. On this dataset that’s 577 [4]. A single fraud pattern in a batch generates 577 instances the gradient of a non-fraud one.
pos_weight = rely(y=0) / rely(y=1) ≈ 577
That weight gives a directional sign when labeled fraud does seem. However the mannequin nonetheless has no idea of what “suspicious” seems to be like in characteristic area — it solely is aware of that fraud examples, once they do present up, ought to be closely weighted. That’s totally different from understanding the place to look on batches that occur to comprise no labeled fraud in any respect.
The Rule Loss
Right here is the core thought. Fraud analysts know two issues empirically: unusually excessive transaction quantities are suspicious, and transactions that sit removed from regular habits in PCA area are suspicious. I would like the mannequin to assign excessive fraud possibilities to transactions that match each alerts — even when a batch accommodates no labeled fraud examples.
The trick is making the rule differentiable. An if/else threshold — flag any transaction the place quantity > 1000 — is a tough step operate. Its gradient is zero in all places besides on the threshold itself, the place it’s undefined. Which means backpropagation has nothing to work with; the rule produces no helpful gradient sign and the optimizer ignores it. As a substitute, I take advantage of a steep sigmoid centered on the batch imply. It approximates the identical threshold habits however stays clean and differentiable in all places — the gradient is small removed from the boundary and peaks close to it, which is precisely the place you need the optimizer paying consideration. The result’s a clean suspicion rating between 0 and 1:
def rule_loss(x, probs):
# x[:, -1] = Quantity (final column in creditcard.csv after dropping Class)
# x[:, 1:29] = V1–V28 (PCA parts, columns 1–28)
quantity = x[:, -1]
pca_norm = torch.norm(x[:, 1:29], dim=1)
suspicious = (
torch.sigmoid(5 * (quantity - quantity.imply())) +
torch.sigmoid(5 * (pca_norm - pca_norm.imply()))
) / 2.0
penalty = suspicious * torch.relu(0.6 - probs.squeeze())
return penalty.imply()
A observe on why PCA norm particularly: the V1–V28 options are the results of a PCA rework utilized to the unique anonymized transaction knowledge. A transaction that sits removed from the origin on this compressed area has uncommon variance throughout a number of unique options concurrently — it’s an outlier within the latent illustration. The Euclidean norm of the PCA vector captures that distance in a single scalar. This isn’t a Kaggle-specific trick. On any dataset the place PCA parts symbolize regular behavioral variance, the norm of these parts is an inexpensive proxy for atypicality. In case your options will not be PCA-transformed, you’ll substitute this with a domain-appropriate sign — Mahalanobis distance, isolation rating, or a feature-specific z-score.
The relu(0.6 – probs) time period is the constraint: it fires solely when the mannequin’s predicted fraud likelihood is under 0.6 for a suspicious transaction. If the mannequin is already assured (prob > 0.6), the penalty is zero. That is intentional — I’m not penalizing the mannequin for being too aggressive on suspicious transactions, just for being too conservative. The asymmetry means the rule can by no means combat in opposition to an accurate high-confidence prediction.
Formally, the mixed goal is:
L_total = L_BCE + λ · L_rule
L_rule = E[ σ_susp(x) · ReLU(0.6 − p) ]
σ_susp(x) = ½ · [ σ(5·(amount − ā)) + σ(5·(‖V₁₋₂₈‖ − mean‖V‖)) ]
The λ hyperparameter controls how onerous the rule pushes. At λ=0 you get the pure neural baseline. The total coaching loop:
for xb, yb in train_loader:
xb, yb = xb.to(DEVICE), yb.to(DEVICE)
logits = mannequin(xb)
bce = criterion(logits.squeeze(), yb)
probs = torch.sigmoid(logits)
rl = rule_loss(xb, probs)
loss = bce + lambda_rule * rl
optimizer.zero_grad()
loss.backward()
optimizer.step()
Tuning Lambda
5 values examined: 0.0, 0.1, 0.5, 1.0, 2.0. Every mannequin skilled to greatest validation PR-AUC with early stopping at endurance=7, seed=42:
Lambda 0.0 → Val PR-AUC: 0.7580
Lambda 0.1 → Val PR-AUC: 0.7595
Lambda 0.5 → Val PR-AUC: 0.7620 ← greatest
Lambda 1.0 → Val PR-AUC: 0.7452
Lambda 2.0 → Val PR-AUC: 0.7504
Greatest Lambda: 0.5
λ=0.5 wins narrowly on validation PR-AUC. The hole between λ=0.0, 0.1, and 0.5 is small — throughout the vary of seed variance because the multi-seed evaluation under reveals. The significant drop at λ=1.0 and a pair of.0 means that aggressive rule weighting can override the BCE sign slightly than complement it. On new knowledge, deal with λ=0 because the default and confirm any enchancment holds throughout seeds earlier than trusting it.
One factor to watch out about with threshold choice: I computed the optimum F1 threshold on the validation set and utilized it to the take a look at set — for each fashions symmetrically. On a 0.17% positive-rate dataset, the optimum determination boundary is nowhere close to 0.5. Making use of totally different thresholding methods to totally different fashions means measuring the brink hole, not the mannequin hole. Each should use the identical strategy:
def find_best_threshold(y_true, probs):
precision, recall, thresholds = precision_recall_curve(y_true, probs)
f1_scores = 2*(precision*recall) / (precision+recall+1e-8)
return thresholds[np.argmax(f1_scores)]
# Utilized symmetrically to BOTH fashions — val set solely
hybrid_thresh, _ = find_best_threshold(y_val, hybrid_val_probs)
pure_thresh, _ = find_best_threshold(y_val, pure_val_probs)
Outcomes
| Mannequin | F1 | PR-AUC | ROC-AUC | Recall@1percentFPR |
| Isolation Forest | 0.121 | 0.172 | 0.941 | 0.581 |
| One-Class SVM | 0.029 | 0.391 | 0.930 | 0.797 |
| Pure Neural (λ=0) | 0.776 | 0.806 | 0.969 | 0.878 |
| Hybrid (λ=0.5) | 0.767 | 0.745 | 0.970 | 0.878 |
On this seed, the hybrid and pure baseline are aggressive on F1 (0.767 vs 0.776) and equivalent on Recall@1percentFPR. The hybrid’s PR-AUC is decrease on this explicit seed (0.745 vs 0.806). The cleanest sign is ROC-AUC — 0.970 for the hybrid vs 0.969 for the pure baseline. ROC-AUC is threshold-independent, measuring rating high quality throughout all potential cutoffs. That edge is the place the rule loss reveals up most constantly.
Precision-Recall Curve

Robust early precision is what you need in a fraud system. The curve holds moderately earlier than dropping — which means the mannequin’s top-ranked transactions are genuinely fraud-heavy, not only a fortunate threshold. In manufacturing you’ll tune the brink to your precise price ratio: the price of a missed fraud versus the price of a false alarm. The val-optimized F1 threshold used here’s a cheap center floor for reporting, not the one legitimate alternative.
Confusion Matrix

Rating Distributions

This histogram is what I have a look at first after coaching any classifier on imbalanced knowledge. The non-fraud distribution ought to spike close to zero; the fraud distribution ought to unfold towards 1. The overlap area within the center is the place the mannequin is genuinely unsure — that’s the place your threshold lives.
Variance Evaluation — 5 Random Seeds
A single-seed end result on a dataset this imbalanced just isn’t sufficient to belief. I ran each fashions throughout seeds [42, 0, 7, 123, 2024], making use of val-optimized thresholds symmetrically to each in each run:
Seed 42 | Hybrid F1: 0.767 PR-AUC: 0.745 | Pure F1: 0.776 PR-AUC: 0.806
Seed 0 | Hybrid F1: 0.733 PR-AUC: 0.636 | Pure F1: 0.788 PR-AUC: 0.743
Seed 7 | Hybrid F1: 0.809 PR-AUC: 0.817 | Pure F1: 0.767 PR-AUC: 0.755
Seed 123 | Hybrid F1: 0.797 PR-AUC: 0.756 | Pure F1: 0.757 PR-AUC: 0.731
Seed 2024 | Hybrid F1: 0.764 PR-AUC: 0.745 | Pure F1: 0.826 PR-AUC: 0.763
| Mannequin | F1 (imply ± std) | PR-AUC (imply ± std) | ROC-AUC (imply ± std) |
| Pure Neural | 0.783 ± 0.024 | 0.760 ± 0.026 | 0.967 ± 0.003 |
| Hybrid (λ=0.5) | 0.774 ± 0.027 | 0.740 ± 0.058 | 0.970 ± 0.005 |

Three observations from the variance knowledge. The hybrid wins on F1 in 2 of 5 seeds; the pure baseline wins in 3 of 5. Neither dominates on threshold-dependent metrics. The hybrid’s PR-AUC variance is notably greater (±0.058 vs ±0.026), which means the rule loss makes some initializations higher and a few worse — it’s a sensitivity, not a assured enchancment. The one end result that holds with out exception: ROC-AUC is greater for the hybrid throughout all 5 seeds. That’s the cleanest sign from this experiment.
Why Does the Rule Loss Assist ROC-AUC?
ROC-AUC is threshold-independent — it measures how effectively the mannequin ranks fraud above non-fraud throughout all potential cutoffs. A constant enchancment throughout 5 seeds is an actual sign. Here’s what I believe is occurring.
With 0.172% fraud prevalence, most 2048-sample batches comprise solely 3–4 labeled fraud examples. The BCE loss receives virtually no fraud-relevant gradient on nearly all of batches. The rule loss fires on each suspicious transaction no matter label — it generates gradient alerts on batches that will in any other case inform the optimizer virtually nothing about fraud. This provides the mannequin constant path all through coaching, not simply on the uncommon batches the place labeled fraud occurs to seem.
The penalty can be feature-selective. By pointing the mannequin particularly towards quantity and PCA norm, the rule reduces the prospect that the mannequin latches onto irrelevant correlations within the different 28 dimensions. It features as tender regularization over the characteristic area, not simply the output area.
The one-sided relu issues too. I’m not penalizing the mannequin for being too aggressive on suspicious transactions — just for being too conservative. The rule can’t combat in opposition to an accurate high-confidence prediction, solely push up underconfident ones. That asymmetry is deliberate.
The lesson just isn’t that guidelines substitute studying. It’s that guidelines can information it — particularly when labeled examples are scarce and also you already know one thing about what you might be in search of.
On Threshold Analysis in Imbalanced Classification
One discovering from this experiment is price its personal part as a result of it applies to any imbalanced classification downside, not simply fraud.
On a dataset with 0.17% optimistic charge, the optimum F1 threshold is nowhere close to 0.5. A mannequin can rank fraud virtually completely and nonetheless rating poorly on F1 at a default threshold, just because the choice boundary must be calibrated to the category imbalance. Which means if two fashions are evaluated with totally different thresholding methods — one at a hard and fast cutoff, the opposite with a val-optimized cutoff — you aren’t evaluating fashions. You might be measuring the brink hole.
The sensible guidelines for clear comparability on imbalanced knowledge:
- Each fashions evaluated with the similar thresholding technique
- Threshold chosen on validation knowledge, by no means on take a look at knowledge
- PR-AUC and ROC-AUC reported alongside F1 — each are threshold-independent
- Variance throughout a number of seeds to separate actual variations from fortunate initialization
Issues to Watch Out For
Batch-relative statistics. The rule computes “excessive quantity” and “excessive PCA norm” relative to the batch imply, not a hard and fast inhabitants statistic. Throughout coaching with massive batches (2048) and stratified sampling, batch means are steady sufficient. In on-line inference scoring particular person transactions, freeze these statistics to training-set values. In any other case the “suspicious” boundary shifts with each name.
PR-AUC variance will increase with the rule loss. Hybrid PR-AUC ranges from 0.636 to 0.817 throughout seeds versus 0.731 to 0.806 for the pure baseline. A rule that helps on some initializations and hurts on others requires multi-seed validation earlier than drawing conclusions. Single-seed outcomes will not be sufficient.
Excessive λ degrades efficiency. λ=1.0 and a pair of.0 present a significant drop in validation PR-AUC. Aggressive rule weighting can override the BCE sign slightly than complement it. Begin at λ=0.5 and confirm by yourself knowledge earlier than going greater.
A pure extension would make the rule weights learnable slightly than mounted at 0.5/0.5:
# Learnable mixture weights
self.rule_w = nn.Parameter(torch.tensor([0.5, 0.5]))
w = torch.softmax(self.rule_w, dim=0)
suspicious = (
w[0] * torch.sigmoid(5 * (quantity - quantity.imply())) +
w[1] * torch.sigmoid(5 * (pca_norm - pca_norm.imply()))
)
This lets the mannequin resolve whether or not quantity or PCA norm is extra predictive for the particular knowledge, slightly than hard-coding equal weights. This variant has not been run but — it’s the subsequent factor on the listing.
Closing Ideas
The rule loss does one thing actual — the ROC-AUC enchancment is constant and threshold-independent throughout all 5 seeds. The advance on threshold-dependent metrics like F1 and PR-AUC is inside noise vary and is determined by initialization. The sincere abstract: area guidelines injected into the loss operate can enhance a mannequin’s underlying rating distributions on rare-event knowledge, however the magnitude relies upon closely on the way you measure it and the way steady the development is throughout seeds.
When you work in fraud detection, anomaly detection, or any area the place labeled positives are uncommon and area data is wealthy, this sample is price experimenting with. The implementation is easy — a handful of strains on high of a normal coaching loop. The extra necessary self-discipline is measurement: use symmetric threshold analysis, report threshold-independent metrics, and all the time run a number of seeds earlier than trusting a end result.
The repo has the complete coaching loop, lambda sweep, variance evaluation, and eval code. Obtain the CSV from Kaggle, drop it in the identical listing, run app.py. The numbers above ought to reproduce — if they don’t in your machine, open a problem and I’ll have a look.
References
[1] A. Dal Pozzolo, O. Caelen, R. A. Johnson and G. Bontempi, Calibrating Chance with Undersampling for Unbalanced Classification (2015), IEEE SSCI. https://dalpozz.github.io/static/pdf/SSCI_calib_final_noCC.pdf
[2] ULB Machine Studying Group, Credit score Card Fraud Detection Dataset (Kaggle). https://www.kaggle.com/datasets/mlg-ulb/creditcardfraud (Open Database license)
[3] S. Ioffe and C. Szegedy, Batch Normalization: Accelerating Deep Community Coaching by Lowering Inside Covariate Shift (2015), arXiv:1502.03167. https://arxiv.org/abs/1502.03167
[4] PyTorch Documentation — BCEWithLogitsLoss. https://pytorch.org/docs/steady/generated/torch.nn.BCEWithLogitsLoss.html
[5] Experiment code and reproducibility supplies. https://github.com/Emmimal/neuro-symbolic-fraud-pytorch/
Disclosure
This text relies on unbiased experiments utilizing publicly out there knowledge (Kaggle Credit score Card Fraud dataset) and open-source instruments (PyTorch). No proprietary datasets, firm assets, or confidential data had been used. The outcomes and code are totally reproducible as described, and the GitHub repository accommodates the whole implementation. The views and conclusions expressed listed here are my very own and don’t symbolize any employer or group.

