Screening Test Calculator: A Comprehensive Guide
Understanding Bayesian Probability in Clinical Practice
ClinicoPath
2025-07-13
Source:vignettes/meddecide-35-screening-calculator-comprehensive.Rmd
meddecide-35-screening-calculator-comprehensive.Rmd
Introduction
The Screening Test Calculator is a powerful tool for understanding how diagnostic test characteristics interact with disease prevalence to determine the clinical value of test results. This guide demonstrates how to use Bayes’ theorem in clinical practice through realistic scenarios and sequential testing examples.
Key Learning Objectives
After reading this guide, you will understand:
- How sensitivity, specificity, and prevalence affect predictive values
- When screening tests work well (and when they don’t)
- How to interpret likelihood ratios in clinical practice
- The power of sequential testing and confirmatory tests
- Real-world applications across medical specialties
What Makes This Calculator Special
Unlike simple calculators that just compute numbers, this tool:
- Provides clinical context with real-world scenarios
- Demonstrates sequential testing showing how probabilities update with each test
- Includes Fagan nomograms for visual probability assessment
- Offers extensive example datasets from multiple medical specialties
- Validates inputs and provides clinical plausibility warnings
Understanding the Fundamentals
Bayes’ Theorem in Medicine
The screening calculator applies Bayes’ theorem to medical testing:
Prior Probability (Prevalence) + Test Result → Posterior Probability (Predictive Value)
Key Formulas
Positive Predictive Value (PPV):
PPV = (Sensitivity × Prevalence) / [(Sensitivity × Prevalence) + (1-Specificity) × (1-Prevalence)]
Negative Predictive Value (NPV):
NPV = (Specificity × (1-Prevalence)) / [(Specificity × (1-Prevalence)) + (1-Sensitivity) × Prevalence]
Likelihood Ratios:
Positive LR = Sensitivity / (1-Specificity)
Negative LR = (1-Sensitivity) / Specificity
Clinical Interpretation Guidelines
Metric | Range | Clinical Meaning |
---|---|---|
PPV | <10% | High false positive rate - confirmatory testing essential |
PPV | 10-50% | Moderate confidence - consider additional testing |
PPV | 50-80% | Good confidence - proceed with clinical follow-up |
PPV | >80% | Excellent confidence - high likelihood of disease |
NPV | >95% | Disease can be confidently ruled out |
LR+ | >10 | Strong evidence for disease |
LR+ | 5-10 | Moderate evidence for disease |
LR+ | 2-5 | Weak evidence for disease |
LR- | <0.1 | Strong evidence against disease |
Example Data and Scenarios
Loading the Example Datasets
The package includes five comprehensive datasets with realistic clinical scenarios:
# Load all screening calculator datasets
data(screening_examples)
data(prevalence_demo)
data(performance_demo)
data(sequential_demo)
data(common_tests)
# Display overview of main clinical scenarios
kable(screening_examples[1:5, c("scenario", "setting", "sensitivity", "specificity", "prevalence", "ppv")],
caption = "Sample Clinical Scenarios",
digits = 3)
COVID-19 Testing Scenarios
Let’s examine how COVID-19 rapid tests perform in different settings:
covid_data <- screening_examples[screening_examples$scenario == "COVID-19 Rapid Test", ]
kable(covid_data[, c("setting", "prevalence", "ppv", "npv", "interpretation")],
caption = "COVID-19 Rapid Test Performance by Setting",
digits = 3)
Key Insights:
- Community screening (2% prevalence): Only 26% of positive tests are true positives
-
Outbreak testing (15% prevalence): 78% of positive
tests are true positives
- Symptomatic patients (40% prevalence): 94% of positive tests are true positives
This demonstrates the critical importance of prevalence in test interpretation!
Cancer Screening Examples
Mammography shows the classic challenge of cancer screening:
mammo_data <- screening_examples[screening_examples$scenario == "Mammography Screening", ]
kable(mammo_data[, c("setting", "prevalence", "sensitivity", "specificity", "ppv", "npv")],
caption = "Mammography Performance by Age Group",
digits = 3)
Even with good test characteristics (80-85% sensitivity, 88-92% specificity), PPV remains low due to low cancer prevalence. This explains why positive mammograms require tissue confirmation.
Prevalence Effects: The Most Important Concept
Demonstration with Fixed Test Performance
# Use the prevalence demo data
prevalence_plot_data <- prevalence_demo %>%
select(prevalence, ppv, npv) %>%
tidyr::pivot_longer(cols = c(ppv, npv), names_to = "metric", values_to = "value")
ggplot(prevalence_plot_data, aes(x = prevalence, y = value, color = metric)) +
geom_line(size = 1.2) +
geom_point(size = 3) +
scale_x_log10(labels = scales::percent) +
scale_y_continuous(labels = scales::percent, limits = c(0, 1)) +
labs(title = "How Disease Prevalence Affects Predictive Values",
subtitle = "Fixed test performance: Sensitivity = 90%, Specificity = 90%",
x = "Disease Prevalence (log scale)",
y = "Predictive Value",
color = "Metric") +
theme_minimal() +
theme(legend.position = "bottom")
Sequential Testing: The Power of Multiple Tests
HIV Testing Example
HIV testing demonstrates the power of sequential testing:
hiv_data <- screening_examples[screening_examples$scenario == "HIV Testing", ]
kable(hiv_data[, c("setting", "prevalence", "ppv", "clinical_action")],
caption = "HIV Testing: From Screening to Confirmation",
digits = 3)
The progression from 9% PPV (general population screening) to >99% (confirmatory testing) shows how sequential testing transforms diagnostic certainty.
Mathematical Progression
# Show how probability evolves through testing
sequential_data <- sequential_demo
kable(sequential_data[, c("test_sequence", "final_probability")],
caption = "Disease Probability Evolution Through Sequential Testing",
digits = 3)
ggplot(sequential_data, aes(x = test_sequence, y = final_probability)) +
geom_col(fill = "steelblue", alpha = 0.7) +
geom_text(aes(label = paste0(round(final_probability * 100, 1), "%")),
vjust = -0.5, size = 4) +
scale_y_continuous(labels = scales::percent, limits = c(0, 1)) +
labs(title = "Disease Probability After Sequential Testing",
subtitle = "Sensitivity = 85%, Specificity = 90%, Initial Prevalence = 10%",
x = "Test Sequence Pattern",
y = "Final Disease Probability") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
Practical Clinical Applications
When to Use the Screening Calculator
1. Evaluating Screening Programs
- Determine appropriate populations for screening
- Calculate expected false positive rates
- Plan confirmatory testing strategies
2. Diagnostic Test Interpretation
- Understand confidence levels in test results
- Plan sequential testing approaches
- Counsel patients about test limitations
Test Performance Comparison
# Create heatmap showing PPV across different sens/spec combinations
ggplot(performance_demo, aes(x = factor(specificity), y = factor(sensitivity), fill = ppv)) +
geom_tile() +
geom_text(aes(label = round(ppv, 2)), color = "white", size = 4) +
scale_fill_gradient(low = "red", high = "green", name = "PPV", labels = scales::percent) +
labs(title = "Positive Predictive Value Heatmap",
subtitle = "Fixed prevalence = 10%",
x = "Specificity",
y = "Sensitivity") +
theme_minimal()
Using the Calculator in jamovi
Step-by-Step Guide
1. Basic Setup
- Navigate to meddecide → Decision → Screening Test Calculator
- Enter test characteristics:
- Sensitivity: True positive rate (0.01 to 0.99)
-
Specificity: True negative rate (0.01 to
0.99)
- Prevalence: Disease prevalence in your population (0.001 to 0.999)
Advanced Clinical Scenarios
Multi-Stage Diagnostic Pathways
Coronary Artery Disease Detection
# Simulate a typical CAD diagnostic pathway
cad_pathway <- data.frame(
Stage = c("Pre-test", "After Stress Test", "After Catheterization"),
Test = c("Clinical Assessment", "Exercise Stress Test", "Cardiac Catheterization"),
Prevalence = c(0.25, 0.70, 0.95),
Test_Performance = c("N/A", "Sens 85%, Spec 75%", "Sens 95%, Spec 98%"),
Clinical_Action = c("Risk stratification", "Consider catheterization", "Treatment planning")
)
kable(cad_pathway, caption = "Coronary Artery Disease: Multi-Stage Diagnostic Pathway")
Breast Cancer Screening and Diagnosis
breast_pathway <- data.frame(
Stage = c("Population Screening", "Abnormal Mammogram", "Tissue Diagnosis"),
Prevalence = c("0.8%", "7.2%", "92%"),
PPV = c("N/A", "7.2%", "92%"),
Next_Step = c("Annual mammography", "Tissue biopsy", "Treatment planning"),
False_Positive_Rate = c("N/A", "93%", "8%")
)
kable(breast_pathway, caption = "Breast Cancer: From Screening to Diagnosis")
Outbreak Investigation Scenarios
During disease outbreaks, prevalence changes dramatically:
outbreak_data <- data.frame(
Setting = c("Pre-outbreak", "Early outbreak", "Peak outbreak", "Post-outbreak"),
Estimated_Prevalence = c(0.001, 0.05, 0.20, 0.02),
PPV_Rapid_Test = c(0.08, 0.46, 0.81, 0.26),
Clinical_Strategy = c("Standard screening", "Enhanced surveillance", "Containment focus", "Return to baseline")
)
kable(outbreak_data,
caption = "COVID-19 Testing Strategy by Outbreak Phase",
digits = 2)
Statistical Concepts and Calculations
Understanding Likelihood Ratios
Likelihood ratios quantify how much a test result changes disease probability:
lr_guide <- data.frame(
LR_Positive = c(">10", "5-10", "2-5", "1-2", "<1"),
Evidence_For = c("Strong", "Moderate", "Weak", "Minimal", "Against"),
LR_Negative = c("<0.1", "0.1-0.2", "0.2-0.5", "0.5-1", ">1"),
Evidence_Against = c("Strong", "Moderate", "Weak", "Minimal", "For")
)
kable(lr_guide, caption = "Likelihood Ratio Interpretation Guide")
Probability Conversion
Converting between odds and probabilities:
conversion_examples <- data.frame(
Probability = c(0.01, 0.05, 0.10, 0.25, 0.50, 0.75, 0.90),
Odds = c("1:99", "1:19", "1:9", "1:3", "1:1", "3:1", "9:1"),
Clinical_Context = c("Rare disease", "Uncommon", "Screening", "Symptomatic", "50-50", "Likely", "Very likely")
)
kable(conversion_examples, caption = "Probability to Odds Conversion Examples")
Case Studies
Case Study 1: PSA Screening Dilemma
Scenario: 55-year-old man with elevated PSA (4.5 ng/mL)
Test Characteristics: - Sensitivity: 70% -
Specificity: 80%
- Prevalence in this age group: 3%
Calculations:
psa_ppv <- (0.70 * 0.03) / ((0.70 * 0.03) + (0.20 * 0.97))
psa_npv <- (0.80 * 0.97) / ((0.80 * 0.97) + (0.30 * 0.03))
cat("PSA Screening Results:\n")
cat("PPV =", round(psa_ppv * 100, 1), "%\n")
cat("NPV =", round(psa_npv * 100, 1), "%\n")
cat("\nClinical Interpretation:\n")
cat("- Only", round(psa_ppv * 100, 1), "% of positive PSA tests indicate cancer\n")
cat("- Tissue biopsy needed for confirmation\n")
cat("- Consider patient preferences and comorbidities\n")
Case Study 2: COVID-19 Contact Tracing
Scenario: Contact of confirmed COVID-19 case, asymptomatic
Initial rapid test: Negative Question: How confident can we be that they don’t have COVID-19?
# Scenario parameters
covid_sens <- 0.85
covid_spec <- 0.95
covid_prev_contact <- 0.15 # Higher prevalence as a contact
# Calculate NPV
covid_npv <- (covid_spec * (1 - covid_prev_contact)) /
((covid_spec * (1 - covid_prev_contact)) + ((1 - covid_sens) * covid_prev_contact))
cat("COVID-19 Contact Tracing:\n")
cat("Negative rapid test NPV =", round(covid_npv * 100, 1), "%\n")
cat("Probability of disease despite negative test =", round((1-covid_npv) * 100, 1), "%\n")
cat("\nRecommendation: Consider repeat testing or quarantine period\n")
Troubleshooting and Common Mistakes
Common Input Errors
1. Confusing Sensitivity and Specificity
- Sensitivity: How often the test is positive when disease is present
- Specificity: How often the test is negative when disease is absent
Best Practices and Recommendations
For Clinical Practice
1. Before Ordering Tests
- Estimate pre-test probability
- Consider what you’ll do with results
- Plan for positive AND negative results
For Education and Training
1. Teaching Bayes’ Theorem
- Start with prevalence effects
- Use realistic clinical scenarios
- Demonstrate with visual tools (Fagan nomograms)
Advanced Topics
Test Combinations and Parallel Testing
When multiple tests are performed simultaneously:
# Example: Combined testing approach
parallel_example <- data.frame(
Strategy = c("Test A alone", "Test B alone", "Either positive", "Both positive"),
Sensitivity = c(0.80, 0.70, 0.94, 0.56),
Specificity = c(0.90, 0.95, 0.86, 0.99),
Clinical_Use = c("Standard approach", "Alternative test", "High sensitivity", "High specificity")
)
kable(parallel_example, caption = "Parallel Testing Strategies")
Conclusion
The Screening Test Calculator provides a comprehensive platform for understanding and applying Bayesian probability concepts in clinical practice. By combining rigorous mathematical foundations with practical clinical examples, it bridges the gap between statistical theory and real-world medical decision-making.
Key Takeaways
- Prevalence is crucial: Test performance depends heavily on disease prevalence
-
Sequential testing is powerful: Multiple tests can
dramatically improve diagnostic accuracy
- Context matters: Screening vs. diagnostic contexts require different interpretation
- Clinical judgment remains essential: Tests inform but don’t replace clinical reasoning