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.