Credit risk portfolio
3,000 borrowers and 4,200 commercial loans, where a credit rating actually predicts whether the loan defaults, at the rate S&P's own data says it should.
A credit_score column and a defaulted column with no statistical relationship between them is worse than useless for validating a risk model. Here, PD comes from S&P Global Ratings' own published annual global corporate default rate (averaged across the 2019-2024 studies), LGD comes from the Basel Foundation IRB supervisory value (a number banks are required to use, not one they estimate), and EAD is drawn plus a credit-conversion-factor on undrawn commitment, the real Basel formula. Whether a loan actually defaults is a Bernoulli draw at its borrower's own PD, so AAA, AA, and A show exactly zero defaults, and CCC defaults at close to 28%, both measured directly from these files.
- credit risk
- fintech
- PD LGD EAD
- Basel
- risk modeling
Explore
Every table, profiled
Each column's type, spread, empties and most common values, measured from the CSVs in the download. Switch to the first rows to see the data exactly as it sits in the file.
2 tables
loans.csv
4,200 rows · 14 columns · 1 foreign keys
- senior_unsecured83%
- subordinated17%
- term_loan46%
- long_term_revolving21%
- short_term_revolving19%
- unconditionally_cancellable14%
Keys
Every join resolves
1 foreign key, 4,200 references checked against the table each one points at. None points at a row that does not exist.
loans
- borrower_idborrowers.borrower_id4,200 rows checked0 orphans
Checks
What we checked
- AAA, AA, and A: 0 of 1,067 loans defaulted (S&P published PD: 0.00% for all three)
- BBB: 2 of 1,261 defaulted, 0.16%, against a cited 0.03% PD
- CCC: 88 of 314 defaulted, 28.03%, against a cited 26.92% PD
- senior_unsecured LGD is exactly 40% on all 3,480 such loans, subordinated exactly 75% on all 720
- ead equals drawn_amount + ccf x undrawn_commitment on all 4,200 loans
- expected_loss equals pd x lgd x ead on all 4,200 loans
- realized_loss is 0 on every non-defaulted loan, and equals lgd x ead on every defaulted one
- 0 orphaned foreign keys joining loans to borrowers
The same checks ship in the zip as INTEGRITY.txt, so you can rerun them in any SQL engine. How we verify
Questions
Worth asking it
- 1Does realized default rate actually track PD, by rating grade?
- 2What is the portfolio's total expected loss as a percentage of exposure?
- 3How does expected loss concentrate across seniority and commitment type?
- 4Which industries carry the riskiest rating mix?
Use it
Take it, or make one shaped like yours
Rebuild it byte for byte
pip install misata curl -O https://raw.githubusercontent.com/rasinmuhammed/misata/main/examples/credit_risk_portfolio.py python -c "from credit_risk_portfolio import build, verify; t = build(n_borrowers=3000, seed=11); verify(t)"
This dataset adds a reconcile step on top of the declared schema (PD/LGD/EAD lookups, a real Bernoulli default draw per loan), so it ships as a runnable script rather than a schema.yaml a bare misata generate could regenerate honestly.
Your own tables, your own numbers
Describe the data you need in Studio and get connected tables with the totals you state, profiled like this and checked before you download.
Premium datasets
All premiumWeekly sales, at regular price and on promotion
Grocery chain, 10 stores, fiscal 2024 and 2025
Two fiscal years of a grocery chain, from the shelf to the receipt
Answer key
- baseline_units
- price_effect
- promo_lift
- +7 more
- Rows
- 2,790,852
- Tables
- 14
- Checks
- 117 of 117
Free previewProfile and previewAn X-bar chart with the truth underneath: flatness, characteristic 139
3 plants, 36 CNC machines, six months
Six months of control charts with the ground truth underneath
Answer key
- active_cause_id
- true_cause_shift_sigma
- true_tool_wear_sigma
- +6 more
- Rows
- 515,442
- Tables
- 15
- Checks
- 101 of 101
Free previewProfile and previewVibration through a life that ends in failure
240 machines at 4 plants, two years
Two years of sensor readings, failures, repairs and costs for 240 machines
Answer key
- failure_mode
- true_life_days
- true_failure_at
- +6 more
- Rows
- 179,038
- Tables
- 6
- Checks
- 67 of 67
Free previewProfile and preview
Related free datasets
All 12- Synthetic AML transaction dataset with labelled typologies and ground truthA bank's customers, accounts and transactions, with the laundering typologies labelled, the rule-based alerts raised, and the cases and SARs that followed.44,612 rows · 6 tables
- Retail star schemaA dimensional model you can actually practise joins on: one fact table, four dimensions, 47,051 rows, every join resolving and every total known.47,051 rows · 5 tables
- Machine degradation100 machines monitored from commissioning to failure, with an exact remaining-useful-life label on every one of 23,118 readings.46,336 rows · 3 tables
- Ecommerce storefrontA year of orders across five joined tables, with best sellers, heavy buyers, a real Q4 peak and totals that reconcile to the cent.49,493 rows · 5 tables
- B2B SaaS subscription analyticsAccounts, seats, MRR, churn and support load, where company size actually drives the plan.42,240 rows · 5 tables
- Network intrusion / netflow500 hosts and 20,000 labeled flows, where a port scan, a DDoS flood, and a brute-force attempt each carry the real statistical signature their MITRE ATT&CK technique actually leaves in traffic.20,500 rows · 2 tables
Fully synthetic. No real person, company or transaction is represented, and no production data was read to make it. CC0: use it anywhere, no attribution needed.

