Split a transaction table by a binary status flag (authorized vs. declined, paid vs. refunded) into two parallel sub-tables, then build the same aggregate feature pipeline on each — the declined-transaction features are usually as predictive as the authorized ones because they encode risk and friction the authorized stream alone hides
Scanned 9/12/2026
Install to Claude Code
npx -y skills add wenmin-wu/ds-skills --skill authorized-flag-table-split --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Authorized Flag Table Split?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/wenmin-wu-authorized-flag-table-split)More formats (shields.io, HTML) on the badges page.
---
name: tabular-authorized-flag-table-split
description: Split a transaction table by a binary status flag (authorized vs. declined, paid vs. refunded) into two parallel sub-tables, then build the same aggregate feature pipeline on each — the declined-transaction features are usually as predictive as the authorized ones because they encode risk and friction the authorized stream alone hides
---
## Overview
A common mistake on transaction panels is to filter `authorized_flag == 'Y'` and discard the rest. The declined rows are not noise — they encode declined-rate, declined-amount, declined-merchant-diversity, and other friction signals that strongly correlate with churn, fraud, and loyalty score. Top Elo Merchant solutions all built three parallel feature blocks: (1) full table, (2) authorized-only sub-table, (3) non-authorized sub-table — each through the same `groupby(card_id).agg(...)` pipeline. The model learns from the *contrast*: `auth_amt_mean / nonauth_amt_mean`, `auth_count / total_count`. Generalize to any binary flag — paid/refunded, success/failure, mobile/web.
## Quick Start
```python
auth = tx[tx.authorized_flag == 'Y']
nonauth = tx[tx.authorized_flag == 'N']
def agg_block(df, prefix):
g = df.groupby('card_id').agg(
amt_sum=('purchase_amount', 'sum'),
amt_mean=('purchase_amount', 'mean'),
cnt=('purchase_amount', 'size'),
nuniq_merch=('merchant_id', 'nunique'),
).reset_index()
g.columns = ['card_id'] + [f'{prefix}_{c}' for c in g.columns[1:]]
return g
feat_all = agg_block(tx, 'all')
feat_auth = agg_block(auth, 'auth')
feat_non = agg_block(nonauth, 'nonauth')
cards = feat_all.merge(feat_auth, on='card_id', how='left')\
.merge(feat_non, on='card_id', how='left')
cards['auth_rate'] = cards['auth_cnt'] / cards['all_cnt']
```
## Workflow
1. Identify the binary flag (`authorized_flag`, `paid`, `is_success`)
2. Split the transaction frame into two sub-frames — keep both, do not filter and forget
3. Run the same aggregate pipeline (sum/mean/count/nunique/std) on each sub-frame, plus the union
4. Suffix column names (`auth_*`, `nonauth_*`) so feature importance is self-explanatory
5. Hand-craft 2-3 ratio features post-merge (`auth_rate`, `auth_amt_share`)
6. Left-merge all three blocks onto the entity table; fill NaN with 0 only when 0 is semantically zero (e.g., count), not for means
## Key Decisions
- **Three blocks not two**: the union block is not redundant — it gives the model an unconditional baseline that the splits are deviations from.
- **Ratio features are critical**: `auth_rate` (declined fraction) is usually a top-10 feature on its own.
- **Fill strategy matters**: counts → 0; means/stds → leave NaN so LightGBM can split on missingness directly.
- **Generalizes beyond yes/no**: any low-cardinality status column (3-5 values) can be split this way; cardinality > 10 is too many parallel blocks.
- **Don't double-count in the union**: the union features come from `tx`, not `pd.concat([auth, nonauth])` — they are identical but the latter is slower.
## References
- [Elo World — top-voted Elo Merchant kernel](https://www.kaggle.com/competitions/elo-merchant-category-recommendation)
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!