CRAN check-time reduction; no functional changes. The 0.4.0 submission was auto-rejected by CRAN’s incoming pretests solely for exceeding the 10-minute check-time limit on r-devel-windows.
skip_on_cran(); the complete suite continues to run on
GitHub Actions for every push. CRAN still exercises the optimizer, the
summary tables, the plot, and the whole 0.4.0 evaluation API on compact
search spaces and hand-built definitions.This release focuses on the multi-site validation workflow: everything a collaborator site previously had to hand-code around the package is now built in. It also corrects the ICD-11 operationalization to the field-standard six-item mapping (see Corrections — ICD-11 results change). Apart from that correction, no existing call changes behavior.
create_icd11_diagnosis() — and everything
built on it: the "icd11" fixed criterion in
compare_optimizations(), include_icd11 = TRUE
in evaluate_definitions(), and the ICD-11 row of the
symptom-frequency heatmap — now operationalizes ICD-11 PTSD with the
narrow six-item mapping (items 2, 3, 6, 7, 17, 18; at least one symptom
per cluster). ICD-11 requires re-experiencing with a here-and-now
quality, which nightmares (item 2) and flashbacks (item 3) capture but
intrusive memories (item 1) as worded in the PCL-5 do not; this is the
mapping used across the published PCL-5-to-ICD-11 literature (Kuester et
al. 2017; Schellong et al. 2019; Heeke et al. 2020; Pettrich et
al. 2025). All ICD-11 benchmark results change relative
to earlier versions; because the six-item rule is strictly more
conservative, ICD-11 diagnoses can only become less frequent. The broad
seven-item variant remains available as a custom fixed criterion — see
the recipe in ?create_icd11_diagnosis.as_definitions() converts combinations imported from
JSON into the definitions list evaluate_definitions()
expects, with optional top-n truncation and automatic rule
labels such as "4/6 Hierarchical".
read_combinations() output is now classed
ptsdiag_spec and can be passed to
evaluate_definitions() directly (single spec or a list of
specs — the conversion happens automatically).
write_combinations() gains an optional label
argument stored in the file, so the derivation site controls how each
rule is labelled downstream.evaluate_definitions() gains reference:
validate definitions against an external reference standard (e.g. a
clinician CAPS diagnosis) supplied as a logical vector, a 0/1 column, or
a column name. Rows with a missing reference are excluded with a
message, and a "Full 20-item PCL-5" ceiling row is added by
default (include_full_pcl5) so the cost of the reduced
symptom set can be separated from the intrinsic PCL-5-vs-reference
disagreement.evaluate_definitions() gains tidy (and
as_percent): return a plain analysis table with
Approach / Rank / Combination,
the 2x2 counts, and numeric metrics — the same layout as
summarize_top_combinations(), so derivation and validation
results can be combined with rbind(). No more parsing rule
labels out of the formatted display table.score_all_combinations() scores every
candidate combination (optionally cluster-constrained) against the
DSM-5-TR diagnosis and returns the complete ranked table — the
exhaustive companion to optimize_combinations(), for
interchangeability (“plateau”) analyses. Chunked, with optional parallel
scoring via future.apply like
cross_validation().check_pcl5_data(): exported pre-flight check that
reports every data problem in one pass (column count, numeric type,
integer 0-4 range, missing values) instead of one error at a time, plus
an informational note on all-zero rows. Aimed at collaborator sites
preparing data for rename_ptsd_columns().inst/CITATION: citation("PTSDdiag")
now points to the paper and the package.evaluate_definitions() silently
substituted the default PCL-5 B/C/D/E structure.score_by = "balanced_accuracy" optimization
criterion: maximises balanced accuracy, the mean of sensitivity and
specificity (equivalently, minimises FN/P + FP/N). Available in
optimize_combinations(),
optimize_combinations_clusters(),
compare_optimizations(), holdout_validation(),
and cross_validation(), and accepted as metadata by
write_combinations().Balanced Accuracy column ((sensitivity + specificity)
/ 2) is now reported by summarize_ptsd_changes() (as
balanced_accuracy), create_readable_summary()
(so res$summary, the holdout/cross-validation summaries,
and evaluate_definitions() show it),
summarize_top_combinations(),
compare_diagnostic_systems(), and the cross-validation
combinations_summary (as Balanced_Accuracy).
This makes the reported metric match the quantity the new default
optimizes.score_by = "balanced_accuracy" (was
"accuracy"). In imbalanced samples (the bundled clinical
data is about 94% PTSD-positive) plain accuracy is dominated by the
majority class; balanced accuracy weighs performance in the diagnosed
and non-diagnosed groups equally. Pass
score_by = "accuracy" to reproduce results from earlier
versions.score_by = "balanced_accuracy" requires both diagnosed
and non-diagnosed cases under the reference criterion; data where every
case falls in one class now stops with an informative error suggesting
"accuracy" or "sensitivity".create_readable_summary() now requires a
balanced_accuracy column in its input. Data frames produced
by summarize_ptsd_changes() carry it automatically;
hand-built inputs need the additional column.score_by = "balanced_accuracy" as the standard outcome, and
the Getting started vignette explains the choice among the three
criteria.--run-donttest checks stay fast.create_icd11_diagnosis() now operationalises the ICD-11
“sense of current threat” cluster with PCL-5 items 17 (hypervigilance)
and 18 (exaggerated startle), the symptoms the documentation always
intended. Earlier versions used items 16 (risk-taking behaviour) and 17,
so the ICD-11 benchmark diagnosis, the ICD-11 symptom set reported by
compare_optimizations() / symptom_frequency(),
and any comparison against ICD-11 are affected. Re-run analyses that
benchmarked against ICD-11.extract_definitions() and
evaluate_definitions() are now exported.
extract_definitions() pulls the top-n combinations of each
optimized scenario out of a compare_optimizations() result
(reading each rule from the object) as a portable, shareable object;
evaluate_definitions() applies such a set of mixed-rule
definitions (plus ICD-11) to any sample and returns a performance table.
Together they support multi-site workflows where only symptom-index
definitions, not patient data, are shared.Accuracy column ((TP + TN) / N) is now reported by
create_readable_summary() (so res$summary, the
holdout/cross-validation summaries, and the multi-site tables show it),
summarize_top_combinations(), and
compare_diagnostic_systems(). This makes the reported
metric match the quantity score_by = "accuracy"
optimizes.holdout_validation() and
cross_validation() now default to
score_by = "accuracy" (was "sensitivity"),
matching optimize_combinations() and
compare_optimizations().simulated_ptsd_genpop now also ships paired
clinician-administered CAPS-5 ratings (C1–C20)
for the same participants, simulated to correlate with the PCL-5 items
at a total-score r of about 0.8. The dataset now has 43 columns
(demographics + 20 PCL-5 + 20 CAPS-5); the PCL-5 items and demographics
are unchanged.The score_by argument values have been renamed for
clarity. Pre-0.3.1 values are no longer accepted; passing them errors
with a migration hint.
| Old value (≤ 0.3.0) | New value (0.3.1) | Meaning |
|---|---|---|
"false_cases" |
"accuracy" |
minimise FP + FN (= maximise accuracy) |
"newly_nondiagnosed" |
"sensitivity" |
minimise FN (= maximise sensitivity) |
Defaults updated accordingly: optimize_combinations(),
optimize_combinations_clusters(), and
compare_optimizations() default to "accuracy";
holdout_validation() and cross_validation()
default to "sensitivity".
simulated_ptsd and simulated_ptsd_genpop
now ship with three demographic columns (patient_id,
age, sex) so that the demographic
carry-through workflow (id_col) can be demonstrated
end-to-end on the bundled data. The numerical PCL-5 profile of both
datasets is unchanged.rename_ptsd_columns() /
rename_caps5_columns() when the number of non-ID columns is
not exactly 20 now spells out the strict positional behaviour and points
users at id_col for unrelated covariates.quickstart and folds in
id_column_workflow).internal_analysis and
multi_scenario_analysis).internal_analysis and
external_validation_pcl5).external_validation_caps5).compare_optimizations() runs multiple
symptom-optimization scenarios on the same dataset in a single call and
returns a ptsdiag_comparison S3 object. Default scenarios
reproduce the three approaches compared in the PTSDdiag preprint (4/6
hierarchical, 4/6 non-hierarchical, 3/6 non-hierarchical). Users can
supply their own named list of scenarios with arbitrary
n_symptoms / n_required /
hierarchical combinations.include_icd11 = TRUE
convenience flag or via scenarios entries of
type = "fixed", including user-supplied logical diagnosis
vectors. They appear as additional rows in the comparison table and as
rows of 0/1 cells in the heatmap.summarize_top_combinations() produces a tidy
manuscript-ready table (Approach / Rank / Combination / TP / FN / FP /
TN / Sensitivity / Specificity / PPV / NPV) from a
ptsdiag_comparison. Optional as_percent = TRUE
returns percentages for direct manuscript use.symptom_frequency() returns the long-format Symptom ×
Approach × Count / RelFreq dataframe (source of the preprint’s
Supplementary Table S4), optionally appending an OVERALL pooled
row.plot_symptom_frequency() draws the symptom-selection
heatmap (Figure 1 of the preprint) as a ggplot object, with
the OVERALL row in its own facet for visual separation.
ggplot2 is now in Suggests.id_col carry-through (introduced in 0.2.7) propagates
automatically through every scenario in
compare_optimizations().multi-scenario-analysis replicates the
preprint’s end-to-end derivation workflow in roughly twenty lines of
code.rename_ptsd_columns() and
rename_caps5_columns() gain an id_col
argument: a character vector of column name(s) to preserve through the
workflow as participant identifiers. When supplied, the named columns
are prepended to the renamed dataframe and propagate automatically
through optimize_combinations(),
optimize_combinations_clusters(),
apply_symptom_combinations(),
holdout_validation(), cross_validation(),
create_icd11_diagnosis(), and
create_caps5_diagnosis(). The result of each per-row
function (diagnosis_comparison, test_results,
fold_results, etc.) prepends these ID columns so diagnoses
can be joined back to the original dataframe — for example, to compare
demographics between participants who do and do not meet an optimized
criterion.compare_diagnostic_systems() automatically skips
carry-through ID columns in its ... inputs so they are not
mistaken for diagnostic systems.binarize_data() now mutates only the
symptom_1..symptom_20 columns rather than the
whole dataframe. Any additional columns (e.g. an ID column) are
preserved unchanged. This fixes a latent bug where a non-numeric
carry-through column would have been coerced or errored.create_ptsd_diagnosis_binarized() now operates on the
symptom subset only, accepting input dataframes with extra columns.summarize_ptsd_changes() silently drops non-logical
columns before computing metrics (previously errored). This lets ID
columns ride along in comparison dataframes without breaking downstream
summarization.id-column-workflow demonstrating how to
use id_col to merge per-row diagnoses back to a dataframe
with demographics.cli package
for consistent, rich formatting: argument names are highlighted, actual
values are shown, and hint bullets guide users toward fixes..validate_pcl5_data()
now accepts strict_cols, warn_total, and
instrument parameters, reducing code duplication across
exported functions.holdout_validation() and
cross_validation() now correctly restore the global RNG
state on exit (replaced buggy withr::local_seed() with
manual on.exit save/restore).withr from Imports (no longer used).@note to simulated_ptsd and
simulated_ptsd_genpop dataset documentation clarifying that
symptoms were simulated independently (no within-cluster
correlations).k rejection, empty split guard, and
n_tied output from optimization functions.README.md that still linked to the removed
introduction.html vignette instead of the new
internal_analysis.html.URL field.JamesIves/github-pages-deploy-action to v4.7.3
for Node.js 24 compatibility.create_caps5_diagnosis() applies the DSM-5-TR
diagnostic algorithm to CAPS-5 (Clinician-Administered PTSD Scale for
DSM-5) item scores and returns the clinician-rated diagnostic
status.rename_caps5_columns() standardises CAPS-5 column names
to symptom_1 through symptom_20, enabling all
downstream functions to work transparently on CAPS-5 data.compare_diagnostic_systems() gains a
caps5_data argument for including CAPS-5 diagnoses in the
unified comparison table, and a reference argument
("pcl5" or "caps5") for selecting which
instrument defines diagnostic “truth”. Labels are disambiguated
automatically when both instruments are present
(e.g. "DSM-5-TR (PCL-5)",
"DSM-5-TR (CAPS-5)").create_icd11_diagnosis() applies ICD-11 PTSD diagnostic
criteria to PCL-5 data and returns a comparison dataframe against
DSM-5-TR. Output is directly compatible with
summarize_ptsd_changes().compare_diagnostic_systems() produces a single unified
summary table comparing the diagnostic performance of DSM-5-TR, ICD-11,
and any number of optimised symptom combinations. Output is
knitr::kable()-ready for manuscript tables.create_readable_summary() gains a DT
parameter for optional interactive DT::datatable() widget
output, consistent with the optimisation functions.optimize_combinations() and
optimize_combinations_clusters() gain a
show_progress parameter (default TRUE). Set to
FALSE for batch or non-interactive use.optimize_combinations(),
optimize_combinations_clusters(),
holdout_validation(), and cross_validation()
now return plain data frames by default. Set DT = TRUE for
interactive DT widgets (previous default behaviour).combination_id and
rank columns) is now tracked through the full pipeline:
optimization summaries, write_combinations() /
read_combinations() JSON files, and cross-validation
combination summaries.cli package: fold-level
progress bars in cross_validation() and informational
messages in holdout_validation() and the optimization
functions.cross_validation() supports parallel fold processing
via future.apply when available. Set up with
future::plan(future::multisession) before calling.analyze_best_six_symptoms_four_required() and
analyze_best_six_symptoms_four_required_clusters() are
soft-deprecated in
favour of optimize_combinations() and
optimize_combinations_clusters().
optimize_combinations() and
optimize_combinations_clusters()) instead of legacy
wrappers.optimize_combinations() and
optimize_combinations_clusters() that allow configurable
number of symptoms per combination (n_symptoms), required
threshold (n_required), number of top results
(n_top), and custom cluster definitions
(clusters).apply_symptom_combinations() function for external
validation: apply pre-derived combinations to a new dataset and compare
against DSM-5 baseline.write_combinations() and
read_combinations() functions for exporting and importing
optimized symptom combinations as human-readable JSON files, enabling
collaboration across research groups without sharing raw data.analyze_best_six_symptoms_four_required() and
analyze_best_six_symptoms_four_required_clusters() are
preserved as backward-compatible wrappers with PCL-5 defaults.holdout_validation() and
cross_validation() now accept n_symptoms,
n_required, and n_top parameters.