Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Diagnostic test / biomarker accuracy — sensitivity, specificity, PPV, NPV, likelihood ratios, accuracy from a 2x2 table; ROC curve, AUC, and the optimal cutoff (Youden) for a continuous biomarker; and post-test probability via Bayes. Use when you have test results vs a gold standard (binary 2x2, or a continuous score + true labels) and need to judge how good the test is, pick a threshold, or compute the probability of disease given a result. Emphasizes the prevalence-dependence of PPV/NPV.
.claude/skills/tooluniverse-diagnostic-test-evaluation/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-06 | ✗→✓ | ▲ Improved | 78% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 17% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 51% | 0% |
| case-17 | ✗→✓ | ▲ Improved | 6% | 0% |
| case-18 | ✗→✓ | ▲ Improved | 103% | 0% |
Judge how well a test or biomarker discriminates disease — at a fixed cutoff (2×2) or across all cutoffs (ROC) — and turn a result into a probability of disease.
| You have… | Go to | |---|---| | A 2×2 table (TP/FP/TN/FN) at a fixed cutoff | Step 1 (Epidemiology_diagnostic) | | A continuous biomarker score + true labels | Step 2 (ROC / AUC / Youden, Python) | | A test's sens/spec + a patient's pre-test probability | Step 3 (Epidemiology_bayesian) |
bashtu run Epidemiology_diagnostic '{"operation":"diagnostic","tp":90,"fp":10,"tn":180,"fn":20}'
Returns sensitivity, specificity, PPV, NPV, accuracy, LR_pos, LR_neg, and the sample prevalence.
| Metric | Question it answers | Depends on prevalence? | |---|---|---| | Sensitivity = TP/(TP+FN) | Of those WITH disease, what fraction test positive? | No | | Specificity = TN/(TN+FP) | Of those WITHOUT disease, what fraction test negative? | No | | PPV = TP/(TP+FP) | If positive, what's the chance of disease? | Yes — strongly | | NPV = TN/(TN+FN) | If negative, what's the chance of being disease-free? | Yes | | LR+ = sens/(1−spec) | How much a positive raises the odds of disease | No | | LR− = (1−sens)/spec | How much a negative lowers the odds | No |
> The PPV/NPV trap. Sensitivity and specificity are properties of the test; PPV and NPV depend on the disease prevalence in the tested population. A test with great sens/spec has poor PPV in a low-prevalence (screening) setting. Never quote PPV/NPV from a case-control design (its 50/50 prevalence is artificial) — compute them for the real-world prevalence with Epidemiology_bayesian (Step 3). Report sensitivity, specificity, and likelihood ratios as the prevalence-independent summary.
When the test is a continuous score, evaluate across all thresholds:
Prefer the ROC_analysis tool — one call returns structured JSON (AUC + bootstrap 95% CI, Youden-optimal cutoff with its sens/spec, optional metrics at a fixed cutoff, and the ROC curve), and works under the MCP server without a shell:
ROC_analysis(scores=[...], labels=[0,1,...]) # inline arrays
ROC_analysis(csv_path="scores.csv", cutoff=0.6) # or a CSV (cols: label, score)The bundled script is the equivalent CLI form:
bashpython skills/tooluniverse-diagnostic-test-evaluation/scripts/roc_analysis.py --input scores.csv # scores.csv columns: label (1=disease, 0=healthy), score (continuous biomarker)
Both report AUC (with a bootstrap 95% CI), the Youden-optimal cutoff (max sensitivity+specificity−1) and its sens/spec.
| AUC | Discrimination | |---|---| | 0.5 | no better than chance | | 0.7–0.8 | acceptable | | 0.8–0.9 | excellent | | >0.9 | outstanding |
Turn a result into the probability of disease for a given pre-test probability/prevalence:
bashtu run Epidemiology_bayesian '{"operation":"bayesian","prevalence":0.10, "sensitivity":0.90,"specificity":0.95,"test_result":"positive"}'
Returns pre_test_odds, the LR, and post_test_probability. This is how you get the real-world PPV: plug the true prevalence in. (Example: a 90%/95% test at 10% prevalence gives a post-positive probability of only ~67%, not 95%.)
tooluniverse-statistical-modeling — logistic regression that produces the score, ORs.tooluniverse-epidemiological-analysis — population-level risk, screening program metrics.tooluniverse-meta-analysis — pool diagnostic accuracy across studies.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-05 | fail→fail | 10,547 | 6,031 | -43% | 1 | 1 | 0% | 2,436 | 1,816 | -25% | 0 | 0 | — |
case-06 | fail→pass | 9,387 | 9,777 | +4% | 1 | 1 | 0% | 1,945 | 3,456 | +78% | 0 | 0 | — |
case-01 | fail→fail | 12,429 | 6,885 | -45% | 1 | 1 | 0% | 2,678 | 1,742 | -35% | 0 | 0 | — |
case-02 | fail→fail | 14,554 | 11,610 | -20% | 1 | 1 | 0% | 2,727 | 3,646 | +34% | 0 | 0 | — |
case-03 | pass→pass | 11,447 | 7,506 | -34% | 1 | 1 | 0% | 2,140 | 2,772 | +30% | 0 | 0 | — |
case-04 | fail→pass | 12,262 | 6,214 | -49% | 1 | 1 | 0% | 2,148 | 2,504 | +17% | 0 | 0 | — |
case-07 | pass→pass | 10,818 | 11,417 | +6% | 1 | 1 | 0% | 2,131 | 3,738 | +75% | 0 | 0 | — |
case-08 | pass→pass | 11,874 | 14,782 | +24% | 1 | 1 | 0% | 2,180 | 3,672 | +68% | 0 | 0 | — |
case-09 | pass→pass | 11,495 | 9,784 | -15% | 1 | 1 | 0% | 1,897 | 3,005 | +58% | 0 | 0 | — |
case-10 | pass→pass | 12,099 | 8,957 | -26% | 1 | 1 | 0% | 2,072 | 3,015 | +46% | 0 | 0 | — |
case-11 | pass→pass | 9,822 | 11,059 | +13% | 1 | 1 | 0% | 1,852 | 3,406 | +84% | 0 | 0 | — |
case-12 | fail→pass | 11,596 | 13,834 | +19% | 1 | 1 | 0% | 2,664 | 4,024 | +51% | 0 | 0 | — |
case-13 | pass→pass | 11,753 | 10,111 | -14% | 1 | 1 | 0% | 2,174 | 3,186 | +47% | 0 | 0 | — |
case-14 | fail→fail | 23,085 | 4,544 | -80% | 1 | 1 | 0% | 2,509 | 1,653 | -34% | 0 | 0 | — |
case-15 | pass→pass | 13,401 | 5,576 | -58% | 1 | 1 | 0% | 1,984 | 2,367 | +19% | 0 | 0 | — |
case-16 | pass→pass | 4,215 | 5,126 | +22% | 1 | 1 | 0% | 870 | 2,299 | +164% | 0 | 0 | — |
case-17 | fail→pass | 10,355 | 3,745 | -64% | 1 | 1 | 0% | 2,110 | 2,240 | +6% | 0 | 0 | — |
case-18 | fail→pass | 5,850 | 5,454 | -7% | 1 | 1 | 0% | 1,250 | 2,534 | +103% | 0 | 0 | — |
case-19 | pass→pass | 9,978 | 6,162 | -38% | 1 | 1 | 0% | 1,788 | 2,326 | +30% | 0 | 0 | — |
case-20 | pass→pass | 4,974 | 3,784 | -24% | 1 | 1 | 0% | 948 | 2,080 | +119% | 0 | 0 | — |
case-21 | pass→pass | 5,827 | 5,392 | -7% | 1 | 1 | 0% | 1,155 | 2,507 | +117% | 0 | 0 | — |
case-22 | pass→pass | 8,226 | 7,885 | -4% | 1 | 1 | 0% | 1,798 | 3,168 | +76% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 19 counted toward the lift figure. The other 3 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +23 percentage points is the difference between those two pass rates over the 19 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.6-flash | verified | 7/28/2026 | 0% |
Other measured skills in the registry, with their headline benchmark lift.