We have one row per alert and a long transaction log behind each one, so most of the work was turning that log into features. For every transaction we calculated how many days before the alert date it happened, and built all the windows (last day, last week, last month and so on) from that.
We ended up with 284 features per alert. We trained LightGBM with pretty heavy regularization and a logistic regression on quantile-transformed features, then averaged their ranks (60/40). Validation is 5-fold stratified CV repeated with 3 seeds. Out-of-fold AUC is .
| File | Rows | One row is | Columns |
|---|
Some things we checked early on:
miqdor_indeksi looks like a standardized log amount. Incoming bank transfers have a floor at −2.912, and each type has its own maximum.17.2% of training alerts were escalated. The rate barely moves over time (16–19% per quarter), so the alert date on its own doesn't help much.
Activity goes down as the alert gets closer: about 3 transactions a day around four months before, and about 1 a day in the last few weeks. The drop at day 179 is only the edge of the 180-day window. The day before the alert is very different: about 40 transactions, nearly all in the last hour (23:00–23:59). We think this burst is what fires the alert. But it looks the same for escalated and dismissed alerts, so it doesn't help separate them.
Escalated customers are a little more active overall (about 6% more transactions), and they have more transactions on the alert date itself.
This was the most useful finding. Escalated customers have smaller amounts: the mean miqdor_indeksi is 0.05–0.09 lower in every window. It shows up most in bank transfers, where small transfers are up to 15% more common and large ones about 30% less common for escalated alerts. Card payments show the same thing, but weaker. Cash shows almost no difference.
We expected cash or international transfers to matter, but the type mix is almost identical between the two groups (within 0.2 percentage points), and so is the incoming/outgoing split. The difference is in the amounts inside each type, so we built amount features for each type and direction separately.
Feature groups we kept:
What we tried and dropped, because CV didn't improve: hour and weekday histograms, features about the last-day burst, in-then-out transfer pairs, CatBoost, and a transaction-level model (AUC 0.556).
| Feature | AUC |
|---|
After the first submission we kept looking for signal the model might be missing. We compared every idea against the same baseline, 5-fold CV repeated with 5 seeds (0.6470 ± 0.0012), so small gains could be told apart from noise.
Three new patterns showed up in the data:
These patterns are real, but they overlap with features the model already had. For example, the floor effect is mostly covered by the bank-transfer amount quantiles. None of the experiments below cleared the +0.005 bar we set before resubmitting, so we kept the original model.
| Experiment | CV AUC |
|---|---|
| Original model (submitted) | 0.6470 |
| + windowed per-type amount quantiles, IQR/MAD, money volume | 0.6475 |
| + burst fine structure, weekly rhythm, hour entropy, in/out transitions, floor counts | 0.6477 |
| + amounts relative to type×direction average (customer amount level) | 0.6478 |
| + full amount histogram per type×direction (78 features) | 0.6460 |
| LightGBM tuning (7 settings) | 0.6431–0.6473 |
| Ensemble of 6 model variants | 0.6482 |
| Top-30 features selected inside each fold | 0.6485 |
We also checked structure outside the transactions: alert ID and file order, how many alerts arrive on the same day, and escalation rate by date, week and month. All of it looked like random noise (AUC 0.49–0.51).