Optimize PTSD Diagnostic Criteria
Overview
Provides tools for analyzing and optimizing PTSD (Post-Traumatic Stress Disorder) diagnostic criteria using PCL-5 (PTSD Checklist for DSM-5) and CAPS-5 (Clinician-Administered PTSD Scale for DSM-5) data. Functions identify optimal subsets of PCL-5 items that maintain diagnostic accuracy while reducing assessment burden. Includes tools for both hierarchical (cluster-based) and non-hierarchical symptom combinations, calculation of diagnostic metrics, and comparison with standard DSM-5 criteria. Redundancy analysis quantifies how many item subsets perform equivalently, through plateau sizes and bootstrap stability, and reports item selection against the chance baseline of the searched candidate space. A transport layer allows a site to evaluate subsets derived elsewhere and return only aggregate summaries, supporting multi-site validation without sharing individual-level data. Model validation is conducted using holdout and cross-validation methods to assess robustness and generalizability of the results. For more details see Weidmann et al. (2025) doi:10.31219/osf.io/6rk72_v1.
This release adds two things. The first is the **redundancy analysis** the
preprint's headline claim rests on: the best symptom combination is rarely
alone, and reporting only the winner overstates how much the data single it out.
The second makes the package self-sufficient for **multi-site validation** — a
site that cannot share its data can now receive a set of symptom combinations
derived elsewhere, evaluate them locally, and return a releasable summary,
without any analysis code living outside the package and without reaching into
unexported internals.
New features
Redundancy analysis
compute_plateau()returns every combination whose balanced accuracy falls withindeltapercentage points of the best in the same search, as a count and as a proportion of that rule form's own candidate space. The denominators matter: a six-item hierarchical search evaluates 13,685 combinations against the non-hierarchical search's 38,760, so the same plateau count means different things.deltadefaults to 1 percentage point and accepts a vector, so a primary and secondary plateau come from one call.
Show all changes in 0.5.0Hide the rest of the changes in 0.5.0
bootstrap_stability()re-runs the entire exhaustive search on bootstrap resamples of the respondents and reports, for every combination, how often it stayed withindeltaof that replicate's best (pi) and how often it was the outright winner (p_argmax, with ties shared equally). Taking the reference point within each replicate rather than from the original sample keeps every comparison on the scale of its own resample. Note thatpifor the combination that won in the original sample is optimistic, since replicates share most of their observations with the sample that selected it; the documentation says so. Per-replicate plateau sizes are returned as well, for a percentile interval across replicates.symptom_selection()reports how often each item appears across the plateau against the chance baseline for that rule form, computed by enumeration rather than assumed. Raw selection counts are zero-sum and cannot be read alone. The baseline is flat atn_symptoms / 20without a cluster constraint, but under the hierarchical rule it ranges from 25.2% for each cognition-and-mood item to 55.8% for each avoidance item, so a flat comparison would make two-item clusters look preferred when they are merely unavoidable. A stability weighted variant is available when abootstrap_stability()result is supplied.plot_symptom_selection()draws those frequencies with the chance baseline marked item by item, or as a ratio to chance.compare_rule_forms()runs the above across a named list of searches and stacks the results into long data frames with arule_formcolumn, ready for a manuscript table.
Multi-site transport and release
evaluate_sets()scores a supplied list of symptom combinations against the full DSM-5-TR PCL-5 diagnosis. Wherescore_all_combinations()enumerates and scores a whole candidate space, this scores exactly the combinations it is given, which is what a validation site needs when the search happened elsewhere. It uses the same collapsed-pattern matrix path asbootstrap_stability(), so cost scales with the number of distinct response patterns rather than with sample size, and it reproducesscore_all_combinations()exactly.transport_plateau()turns those per-combination results into something a site may release: a five-number summary of balanced accuracy, sensitivity and specificity **across** each transported plateau, plus two-by-two counts for a short, pre-specified list of named combinations. The combination-to-value linkage is discarded deliberately — per-combination counts across a whole candidate space are enough constraints to recover the response-pattern distribution, and in a small sample a rare pattern is effectively an individual record. The function has no argument that emits per-combination detail for a plateau, so it cannot be released by accident.write_transport()andread_transport()serialise a return bundle. Every filename is prefixed with the sample identifier and every table carriessample_idandpayload_idcolumns, so bundles from different sites stay distinguishable as loose files in one directory.diris required and must already exist, matchingwrite_combinations(): the package never picks a location for you and never creates directories, so a mistyped path fails instead of scattering files.session_infois off by default.diagnostic_metrics()computes every metric a two-by-two table supports, with intervals, recomputed from the counts. The interval functions behind it are exported too:wilson_ci(),exact_ci()(Clopper-Pearson, for small denominators),ba_ci(),lr_ci()(Simel) andkappa_ci().ba_ci()combines the component intervals by Newcombe square-and-add (see Bug fixes), and every interval here is documented as **marginal**: none is a valid basis for comparing two combinations, which are paired on the same individuals.five_number()reduces a vector to the six numbers a site may release.icd11_items()exposes the six PCL-5 itemscreate_icd11_diagnosis()scores, so a table describing the operationalisation is generated from the same definition that is applied and cannot drift from it.chance_baseline()andn_candidates()expose the size of a candidate space and the proportion of it containing each item. Under a cluster constraint the baseline is a step function of the cluster rather than a constant, because a two-item cluster contributes far more of its combinations than a seven-item one — which is what makes a raw selection frequency misleading on its own.set_id_to_items(),format_set_items(),format_set_labels()andpcl5_item_labels()convert between combination ids and item numbers or labels.as_set_matrix()accepts a combination specification in any of the three shapes the package produces.
Bug fixes
ba_ci()no longer returns a zero-width interval when sensitivity or specificity is at a boundary. The analytic varianceVar(BA) = 0.25 (Var(sens) + Var(spec))is degenerate there, becausep(1-p)/nis zero, so a table with six positives all classified correctly reported1.00 (1.00, 1.00)— no uncertainty at all from 183 observations, while its own component intervals were correctly wide. The default is now Newcombe square-and-add of the component intervals, which is not degenerate at a boundary: the same table gives1.00 (0.80, 1.00)under the defaultmethod = "wilson", and1.00 (0.77, 1.00)undermethod = "exact". The analytic form stays available asmethod = "wald"and warns when a component sits at 0 or 1.diagnostic_metrics(ci = )now reaches balanced accuracy. It previously applied the requested method to the proportions but always used the analytic form for their mean, soci = "exact"returned Clopper-Pearson bounds on sensitivity and specificity next to a Wald interval on balanced accuracy.ba_methodoverrides.- **The hierarchical rule could accept a set spanning one cluster too few.** When
clustersdid not cover all 20 items,.diagnose_combination()counted items belonging to no cluster as though they formed a cluster of their own: the lookup table was sized to the highest clustered item, so an endorsed item above that index read asNAand one inside the range but outside every cluster read as0, andunique()then counted either as a distinct cluster. Withclusters = list(B = 1:5, C = 6:7, D = 8:14), a respondent endorsing items 1, 6 and 15 was diagnosed under a 3-of-3 hierarchical rule despite spanning only two of the three clusters. Items outside every cluster now contribute nothing towards spanning. **Results are unchanged for the standard DSM-5-TR PCL-5 clusters**, which cover all 20 items, so no analysis using the defaults is affected. Affectsoptimize_combinations_clusters(),score_all_combinations()andapply_symptom_combinations()when custom, non-exhaustive clusters were supplied.
Improvements
symptom_frequency()gainsBaselineandEnrichmentcolumns and aclustersargument, for the same reason: selection frequencies over a fixed number of combinations are only interpretable against chance. Existing columns are unchanged.plot_symptom_frequency()gainstype = "enrichment", filling each tile with the ratio of observed to chance selection on a scale diverging around 1. The default remainstype = "relative".
Notes
- The bootstrap collapses respondents to unique binarized response patterns and expresses each replicate as two matrix products, which is exact rather than an approximation because the reference diagnosis and every decision rule depend on the data only through the binarized responses. A full 2,000-replicate run over all 38,760 six-item combinations takes seconds.
- Under the hierarchical rule, items belonging to no cluster count towards the endorsement threshold but not towards spanning the clusters. This follows from the bug fix above and holds identically in the per-row rule and the matrix path, which are checked against each other on every run.
From NEWS.md in the release
Install
Health
- OK13 OK2026-09-08
- ERROR12 OK, 1 ERROR2026-09-07
- OK13 OK2026-08-05
- NOTE12 OK, 1 NOTE2026-08-01
- OK13 OK2026-06-09
Show 2 earlier changesHide 2 earlier changes
- ERROR12 OK, 1 ERROR2026-06-08
- OK14 OK2026-03-10
Documentation
- Help pages
- 63 (1 internal)
- Examples that run
- 71%39 run in a plain check · 16 only when donttest examples are enabled (R CMD check --as-cran)
- Exported functions with examples
- 100%
- Documented parameters
- 91%
- Return-value docs
- 100%
- Help pages citing references
- 2%
Downloads
Repository
- PRs merged (all time)
- 100%
- Median days to close, 50 most recently updated closed issues
- not measured
- Median days to close, 50 most recently updated closed PRs
- not measured
9 development-tooling and community-health practices detected across 5 families in the upstream repository
Checks run against github.com/tobiasrspiller/ptsddiag on 2026-10-11.
The R CMD check workflow runs on Linux, macOS and Windows, and on R-devel
GitHub Pages site last deployed 2026-08-04 · The repository has a site deploy workflow
pkgdown site last built 2026-08-04
Show all practicesHide 1 practice
This repository shows signs of AI coding tools.
- Claude Codefirst seen 2026-02-13Named in .Rbuildignore: .claudePull request it wrote: opened by a project memberCommits: at least 21 crediting it in the message
- Claude Sonnet 4.67 commits · May 2026
- Claude Opus 4.76 commits · May to Jun 2026
- Claude Fable 53 commits · Jun to Jul 2026
- Claude Opus 4.62 commits · Mar to May 2026
- Claude Opus 4.81 commit · Jun 2026
2 more models not listed.
Dependencies
Code & Tests
Datasets
People & History
Pick two releases to compare their code metrics.
- 0.5.0Latest2026-08-04 · current release · diff ↗ ·
added 27 exports
as_set_matrix, ba_ci, bootstrap_stability, chance_baseline, compare_rule_forms, compute_plateau, diagnostic_metrics, evaluate_sets, exact_ci, five_number, fmt_est_ci, fmt_ratio_ci, format_set_items, format_set_labels, icd11_items, icd11_performance, kappa_ci, lr_ci, n_candidates, pcl5_item_labels, plot_symptom_selection, read_transport, set_id_to_items, symptom_selection, transport_plateau, wilson_ci, write_transport - 0.4.12026-07-13 · diff ↗ ·
added 18 exports
apply_symptom_combinations, as_definitions, check_pcl5_data, compare_diagnostic_systems, compare_optimizations, create_caps5_diagnosis, create_icd11_diagnosis, evaluate_definitions, extract_definitions, optimize_combinations, optimize_combinations_clusters, plot_symptom_frequency, read_combinations, rename_caps5_columns, score_all_combinations, summarize_top_combinations, symptom_frequency, write_combinations - RR 4.6.0 released · 2026-04-24
- 0.1.02026-02-13
- RR 4.5.0 released · 2025-04-11
Package metadata
- First published
- 2026-02-13
- Total releases
- 3 / 1 yrs
- License
- MIT + file LICENSE OSI
- Minimum R
- ≥ 3.5.0
- Bundled data
- 55 KB / 2 files
- Download size
- 443 KB
Cite
Cite this package
Run in R for the authors' preferred citation:
citation("PTSDdiag")The package provides a citation file that builds its entry when R runs it. Run citation() to see it.
Cite the R Observatory
For a number measured here: a download total, a coverage figure, an archival date.
From data release v2026-10-18, which the citation names so these numbers can be found later. More on citing and the projects behind them.