Kendalls W#319
Conversation
There was a problem hiding this comment.
Pull request overview
Adds Kendall’s coefficient of concordance (W) to the Reliability module’s Rater Agreement analysis (using irr::kendall()), and refactors the Rater Agreement UI/options around a shared bootstrap/CI + seed “Advanced Options” section. Also adds extensive info tooltips across multiple analyses and updates tests + versioning.
Changes:
- Add Kendall’s W computation + bootstrap CI support to
raterAgreement(R + QML) and extend unit tests with a published reference dataset. - Restructure Rater Agreement options (new
bootstrapSamples, coefficient checkboxes default off) + add upgrade mapping for renamed option. - Add
infometadata to many tables/plots/controls; bump version + updaterenv.lock.
Reviewed changes
Copilot reviewed 27 out of 64 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| R/raterAgreement.R | Adds Kendall’s W + placeholder table; renames bootstrap option usage; adds info strings. |
| inst/qml/RaterAgreement.qml | Adds Kendall’s W UI + “Advanced Options” section for CI/bootstrap/seed; expands allowed variable types. |
| tests/testthat/test-raterAgreement.R | Updates options for new defaults; adds Kendall’s W tests + reference check. |
| tests/testthat/anxietyRatings.csv | New reference dataset for Kendall’s W verification test. |
| inst/Upgrades.qml | Adds rename upgrade: krippendorffsAlphaBootstrapSamplesForCI → bootstrapSamples. |
| R/standardErrorOfMeasurement.R | Adds info metadata; adjusts $dependOn() wiring for CI tables/plots. |
| inst/qml/StandardErrorOfMeasurement.qml | Adds info tooltips across SEM UI controls. |
| R/unidimensionalReliabilityFrequentist.R | Adds info metadata to tables. |
| inst/qml/UnidimensionalReliabilityFrequentist.qml | Adds info tooltips and minor UI restructuring (e.g., Samples section). |
| R/unidimensionalReliabilityBayesian.R | Adds info metadata to tables/containers/plots. |
| inst/qml/UnidimensionalReliabilityBayesian.qml | Adds info tooltips across Bayesian UI controls. |
| R/intraclassCorrelation.R | Adds info metadata to main ICC table. |
| inst/qml/IntraclassCorrelation.qml | Adds info tooltips to ICC controls. |
| R/blandAltman.R | Adds info metadata to Bland–Altman containers/plots/tables. |
| inst/qml/BlandAltman.qml | Adds info tooltips to Bland–Altman controls. |
| NEWS.md | Adds release notes for 0.97.1 (Kendall’s W + UI restructuring). |
| DESCRIPTION | Bumps package version/date. |
| renv.lock | Updates pinned dependency metadata (incl. jaspTools entry) + updates JASP GitHub SHAs. |
| .Rbuildignore | Ignores additional dev directories (.positai, .claude). |
| .gitignore | Ignores .positai. |
| .vscode/settings.json | Adds workspace R LSP setting. |
| inst/Description.qml | Minor formatting change (blank line). |
| inst/help/unidimensionalReliabilityFrequentist.md | Deleted help page. |
| inst/help/unidimensionalReliabilityBayesian.md | Deleted help page. |
| inst/help/standardErrorOfMeasurement.md | Deleted help page. |
| inst/help/raterAgreement.md | Deleted help page. |
| inst/help/intraclassCorrelation.md | Deleted help page. |
| inst/help/toolTip/sampleSavingFreq.md | Deleted tooltip help page (replaced by info). |
| inst/help/toolTip/sampleSavingBayes.md | Deleted tooltip help page (replaced by info). |
| jaspTable <- createJaspTable(title = "Krippendorff's alpha") | ||
| jaspTable$info <- gettext("Krippendorff's alpha: reliability coefficient applicable to any number of raters, any scale level (nominal/ordinal/interval/ratio), and incomplete data.") | ||
| jaspTable$addColumnInfo(name = "method", title = gettext("Method"), type = "string") | ||
| jaspTable$addColumnInfo(name = "kAlpha", title = "Krippendorff's alpha", type = "number") | ||
| jaspTable$position <- 2 |
| .kendallWBootRA <- function(jaspResults, dataset, options, ready) { | ||
| if (!ready || !is.null(jaspResults[["kendallWBootstrapSamples"]]$object)) | ||
| return() | ||
|
|
There was a problem hiding this comment.
is it jaspResults[["kendallWBootstrapSamples"]]$object or jaspResults[["kendallWBootstrapSamples"]] for the null call?
There was a problem hiding this comment.
It's jaspResults[["kendallWBootstrapSamples"]] — guarding on the state element itself, per the module's standard idempotency convention. Fixed here and in the sibling .kripAlphaBoot for consistency. (The old $object form didn't actually error — NULL$object is NULL in R — but this is cleaner.)
| jaspTable$addColumnInfo(name = "W", title = gettext("W"), type = "number") | ||
| jaspTable$addColumnInfo(name = "chisq", title = gettext("Chi-square"), type = "number") | ||
| jaspTable$addColumnInfo(name = "df", title = gettext("df"), type = "integer") | ||
| jaspTable$addColumnInfo(name = "p", title = gettext("p"), type = "pvalue") |
| ^\.positai$ | ||
| ^\.claude$ |
| { | ||
| name: "krippendorffsAlpha" | ||
| label: qsTr("Krippendorff's alpha") | ||
| checked: true | ||
|
|
||
| DropDown | ||
| { | ||
| name: "krippendorffsAlphaMethod" | ||
| label: qsTr("Method") | ||
| values: | ||
| [ | ||
| {label: qsTr("Nominal"), value: "nominal"}, | ||
| {label: qsTr("Ordinal"), value: "ordinal"}, | ||
| {label: qsTr("Interval"), value: "interval"}, | ||
| {label: qsTr("Ratio"), value: "ratio"} | ||
| ] | ||
| } | ||
| IntegerField | ||
| name: "ci" | ||
| label: qsTr("Confidence interval") | ||
| checked: true | ||
| childrenOnSameRow: true |
There was a problem hiding this comment.
Implemented (cbb4262): added id: ciOpt to the CI checkbox; the bootstrap-samples field, CI level, and SetSeed now bind enabled: ciOpt.checked, so the advanced controls are disabled when CI is unchecked.
| info: qsTr("Number of bootstrap replications used to compute confidence intervals. Higher values give more stable estimates.") | ||
| } | ||
|
|
||
| SetSeed {} |
There was a problem hiding this comment.
Implemented (cbb4262): SetSeed now enabled: ciOpt.checked, disabled when the CI box is unchecked (same for the bootstrap-samples field and CI level).
| ciTable$dependOn(optionsFromObject = jaspResults[["semMainContainer"]][["coefficientTable"]], | ||
| options = c("ciLevelTable", "sumScoreCiTable")) | ||
| ciTable$info <- gettext("Confidence intervals for the true score at each sum score level, computed from the conditional SEM.") | ||
| ciTable$dependOn(optionsFromObject = jaspResults[["semMainContainer"]][["coefficientTable"]]) |
| plot$dependOn(optionsFromObject = jaspResults[["semMainContainer"]][["coefficientTable"]], | ||
| options = "combinedPointPlot") | ||
| plot$info <- gettext("Overlay of all selected methods' conditional SEM across the full range of sum scores.") | ||
| plot$dependOn(optionsFromObject = jaspResults[["semMainContainer"]][["coefficientTable"]]) |
| ciPlotsContainer$dependOn(optionsFromObject = jaspResults[["semMainContainer"]][["coefficientTable"]], | ||
| options = c("sumScoreCiPlots", "sumScoreCiPlotsCutoff", "sumScoreCiPlotsCutoffValue", "ciLevelPlots")) | ||
| ciPlotsContainer$info <- gettext("True-score confidence interval plotted against sum score for each selected method.") | ||
| ciPlotsContainer$dependOn(optionsFromObject = jaspResults[["semMainContainer"]][["coefficientTable"]]) |
| @@ -1757,6 +1764,7 @@ unidimensionalReliabilityBayesian <- function(jaspResults, dataset, options) { | |||
| g <- jaspGraphs::themeJasp(g) | |||
|
|
|||
| plot <- createJaspPlot(plot = g, title = "Posterior Predictive Check Omega", width = 350) | |||
| ciTable <- createJaspTable(gettext("Sum Score CI Table")) | ||
| ciTable$dependOn(optionsFromObject = jaspResults[["semMainContainer"]][["coefficientTable"]], | ||
| options = c("ciLevelTable", "sumScoreCiTable")) | ||
| ciTable$info <- gettext("Confidence intervals for the true score at each sum score level, computed from the conditional SEM.") | ||
| ciTable$dependOn(optionsFromObject = jaspResults[["semMainContainer"]][["coefficientTable"]]) | ||
| ciTable$position <- 2 |
| plot$dependOn(optionsFromObject = jaspResults[["semMainContainer"]][["coefficientTable"]], | ||
| options = "combinedPointPlot") | ||
| plot$info <- gettext("Overlay of all selected methods' conditional SEM across the full range of sum scores.") | ||
| plot$dependOn(optionsFromObject = jaspResults[["semMainContainer"]][["coefficientTable"]]) |
| ciPlotsContainer$dependOn(optionsFromObject = jaspResults[["semMainContainer"]][["coefficientTable"]], | ||
| options = c("sumScoreCiPlots", "sumScoreCiPlotsCutoff", "sumScoreCiPlotsCutoffValue", "ciLevelPlots")) | ||
| ciPlotsContainer$info <- gettext("True-score confidence interval plotted against sum score for each selected method.") | ||
| ciPlotsContainer$dependOn(optionsFromObject = jaspResults[["semMainContainer"]][["coefficientTable"]]) |
| .semPointPlots <- function(jaspResults, dataset, options, ready) { | ||
|
|
||
| if (!is.null(jaspResults[["semMainContainer"]][["pointPlots"]]) || !options[["pointPlots"]] | ||
| || !ready || jaspResults[["semMainContainer"]]$getError()) {return()} | ||
|
|
||
| pointPlotsContainer <- createJaspContainer(title = gettext("Point Plots")) | ||
| pointPlotsContainer$info <- gettext("Conditional SEM plotted as a function of sum score for each selected method.") | ||
| pointPlotsContainer$dependOn(optionsFromObject = jaspResults[["semMainContainer"]][["coefficientTable"]], options = "pointPlots") | ||
| jaspResults[["semMainContainer"]][["pointPlotsContainer"]] <- pointPlotsContainer |
| .semSumScoreCiPlots <- function(jaspResults, dataset, options, ready) { | ||
|
|
||
| if (!is.null(jaspResults[["semMainContainer"]][["ciPlots"]]) || !options[["sumScoreCiPlots"]] | ||
| || !ready || jaspResults[["semMainContainer"]]$getError()) {return()} | ||
|
|
||
| nc <- length(unique(c(as.matrix(dataset)))) # may be needed for IRT | ||
|
|
||
| ciPlotsContainer <- createJaspContainer(title = gettext("Sum Score CI Plots")) | ||
| ciPlotsContainer$dependOn(optionsFromObject = jaspResults[["semMainContainer"]][["coefficientTable"]], | ||
| options = c("sumScoreCiPlots", "sumScoreCiPlotsCutoff", "sumScoreCiPlotsCutoffValue", "ciLevelPlots")) | ||
| ciPlotsContainer$info <- gettext("True-score confidence interval plotted against sum score for each selected method.") | ||
| ciPlotsContainer$dependOn(optionsFromObject = jaspResults[["semMainContainer"]][["coefficientTable"]]) | ||
| jaspResults[["semMainContainer"]][["ciPlotsContainer"]] <- ciPlotsContainer |
| jaspTable <- createJaspTable(title = "Krippendorff's alpha") | ||
| jaspTable$info <- gettext("Krippendorff's alpha: reliability coefficient applicable to any number of raters, any scale level (nominal/ordinal/interval/ratio), and incomplete data.") | ||
| jaspTable$addColumnInfo(name = "method", title = gettext("Method"), type = "string") | ||
| jaspTable$addColumnInfo(name = "kAlpha", title = "Krippendorff's alpha", type = "number") |
| .kendallWBootRA <- function(jaspResults, dataset, options, ready) { | ||
| if (!ready || !is.null(jaspResults[["kendallWBootstrapSamples"]]$object)) | ||
| return() | ||
|
|
||
| bootstrapSamples <- createJaspState() | ||
| bootstrapSamples$dependOn(options = c( | ||
| "variables", "kendallW", "ci", "bootstrapSamples", | ||
| "correctForTies", "dataStructure", "setSeed", "seed" | ||
| )) | ||
| jaspResults[["kendallWBootstrapSamples"]] <- bootstrapSamples | ||
|
|
| checked: true | ||
| childrenOnSameRow: true | ||
| id: ciOpt | ||
| info: qsTr("Report a bootstrap confidence interval for each agreement coefficient.") |
| label: qsTr("Confidence interval") | ||
| checked: true | ||
| childrenOnSameRow: true | ||
| id: ciOpt |
| ^\.github$ | ||
| ^tests/upgrades$ | ||
| ^examples$ | ||
| ^jasp_dev_work_dir$ | ||
| ^\.positai$ | ||
| ^\.claude$ |
ef4171f to
354a13e
Compare
CRAN binary for dcurver on aarch64-apple-darwin20 links against libiomp5 (Intel OpenMP), unavailable on CI (fopenmp stripped). Source install compiles without OpenMP. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
jaspTools now uses getFromNamespace instead of sourcing R files, requiring jaspReliability to be loaded before analysisOptions() is called. test-blandAltman and test-intraclassCorrelation ran before library tests that incidentally loaded the package, causing only those two to fail. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…mpat)" This reverts commit ed50a8e.
|
build builder bot! |
| info: qsTr("Number of bootstrap replications used to compute confidence intervals. Higher values give more stable estimates.") | ||
| } | ||
|
|
||
| SetSeed {} |
| { | ||
| name: "krippendorffsAlpha" | ||
| label: qsTr("Krippendorff's alpha") | ||
| checked: true | ||
|
|
||
| DropDown | ||
| { | ||
| name: "krippendorffsAlphaMethod" | ||
| label: qsTr("Method") | ||
| values: | ||
| [ | ||
| {label: qsTr("Nominal"), value: "nominal"}, | ||
| {label: qsTr("Ordinal"), value: "ordinal"}, | ||
| {label: qsTr("Interval"), value: "interval"}, | ||
| {label: qsTr("Ratio"), value: "ratio"} | ||
| ] | ||
| } | ||
| IntegerField | ||
| name: "ci" | ||
| label: qsTr("Confidence interval") | ||
| checked: true | ||
| childrenOnSameRow: true |
|
build builder bot! |
| Upgrade | ||
| { | ||
| functionName: "raterAgreement" | ||
| fromVersion: "0.97.0" | ||
| toVersion: "0.97.1" | ||
|
|
||
| ChangeRename | ||
| { | ||
| from: "krippendorffsAlphaBootstrapSamplesForCI" | ||
| to: "bootstrapSamples" | ||
| } |
There was a problem hiding this comment.
Good catch — fixed in 6f21c58. fromVersion lowered to 0.95.5 (the released version that still carries krippendorffsAlphaBootstrapSamplesForCI); 0.97.0 was never released so the migration was being skipped for real .jasp files.
There was a problem hiding this comment.
Correction to the above after checking the Desktop upgrader source (upgrades.cpp findClosestVersion): a step applies to files saved with fromVersion or lower (Desktop picks the closest step at or above the file's version), not fromVersion-or-higher as assumed here. So the original 0.97.0 was actually fine, and lowering to 0.95.5 (6f21c58) introduced a gap for 0.96.x files (released v0.96.0, master's 0.96.4) — and 0.95.5 was never a release anyway (tags: v0.95.0, v0.95.3, v0.96.0). Fixed in 9b58f31: fromVersion = 0.96.4, the last version carrying the old option name, with a QML comment documenting the or-lower rule. Manually verified: a file saved in JASP 0.96 with a non-default bootstrap count opens in the current build with the value intact.
| { | ||
| "build": ["dcurver"] | ||
| } |
There was a problem hiding this comment.
Intentional. dcurver is a transitive dependency via mirt (used for the IRT SEM analysis), and forcing a source build avoids an OpenMP linker failure on CI (35af3c2). Leaving as-is.
| renv_bootstrap_run <- function(project, libpath, version) { | ||
| tryCatch( | ||
| renv_bootstrap_run_impl(project, libpath, version), | ||
| error = function(e) { | ||
| msg <- paste( | ||
| "failed to bootstrap renv: the project will not be loaded.", | ||
| paste("Reason:", conditionMessage(e)), | ||
| "Use `renv::activate()` to re-initialize the project.", | ||
| sep = "\n" | ||
| ) | ||
| warning(msg, call. = FALSE) | ||
| } | ||
| ) | ||
| } |
There was a problem hiding this comment.
This is auto-generated renv boilerplate (regenerated by renv when its version changes), not hand-authored logic, so not modifying it here.
old option krippendorffsAlphaBootstrapSamplesForCI exists in released 0.95.5; fromVersion 0.97.0 (never released) skipped migration for real .jasp files Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
irr::kappam.fleiss returns per-category detail rows in its own order; categoryKappas was reindexed to sorted categories but categorySE was not, so SE/CI attached to the wrong category when the two orders differed. Reindex the detail matrix once so kappa and SE stay paired. Regenerate the (previously swapped) expected values. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
align .kripAlphaBoot + .kendallWBootRA idempotency guards w/ module convention Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
I did a deeper pass over the current branch, including targeted checks against Correctness issues
Documentation and integration concerns
Tests and scope to examineThe new tests cover point estimates, an explicitly tie-corrected case, and one published dataset, but not:
The originating issue also contains a request for the alternative F-test alongside the large-sample chi-square test. This PR implements only chi-square, so whether the F-test is in or out of scope should be decided explicitly. Minor user-facing mismatches also remain: the Bland-Altman info says the bias line is solid although all three lines are drawn dashed; the Rater Agreement variable tooltip always describes columns as raters even in Verification context: all R sources parse, Windows and both Ubuntu CI jobs pass, and the branch is currently mergeable without code conflicts. macOS and coverage fail before feature tests because of shared dependency/workflow problems also present on master. The targeted statistical reproductions above used the lockfile's R 4.5.2 and |
…ation, type checks) - Kendall W / Kripp alpha: use factor level codes, not alphabetical labels (Kendall per-column codes; Kripp union-of-levels so labels stay aligned across raters) - Kendall boot: listwise-delete + validate before resampling; failed replicates -> NA + footnote instead of aborting analysis - Kendall validation: no all.target names, works with ratersInRows - surface irr ties warning as footnote when correction off - Fleiss: categories from analyzed (complete-case) data, kappas/SEs computed directly from Fleiss-Nee-Landis formulas instead of irr's rounded detail (fixes 0/0 NaN SE for zero kappa, subscript error for deleted categories) - Kripp boot state + table: depend on krippendorffsAlphaMethod; boot wrapped in try - type checks: Cohen/Fleiss reject scale vars, weighted Cohen rejects nominal - update Fleiss expected values (unrounded), add regression tests for all of the above Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- correctForTies default TRUE - bootstrap samples + seed disabled unless a bootstrap-CI coefficient (Kripp alpha / Kendall W) is selected - variables tooltip neutral wrt dataStructure - Bayesian samples tooltip: samples = total iterations incl. burn-in - Bland-Altman plot info: all three lines dashed Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- serialization v3 snapshots require R >= 3.5.0; declare it - renv 1.2.3 ignores the "build" setting so it does not fix the macOS dcurver/OpenMP failure; remove it Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Thanks for the thorough pass — all reproducible. Addressed in a9479f5 (R backend + tests), 3a997e0 (QML), f570a36 (packaging): Correctness
Docs / integration
Tests: ordered factors, ties default/warning, sparse bootstrap, ratersInRows, invalid type combos, deleted-category Fleiss, and zero-kappa Fleiss are all covered now (raterAgreement suite: 27 passing; full suite green locally). Not unit-testable via jaspTools: live Krippendorff method invalidation (see 7) and the .jasp migration (Desktop applies Upgrades.qml at file load, jaspTools has no upgrade machinery) — both now verified manually: method switching recomputes the bootstrap, and a JASP 0.96 file with a non-default bootstrap count keeps its value in the current build (after the fromVersion correction in 9b58f31, see the inline thread). F-test: implemented after all (5921860) — shown alongside the chi-square test (F = (m−1)·W/(1−W), df₁ = n−1−2/m, df₂ = df₁·(m−1); Kendall & Babington Smith 1939, Legendre 2005), cross-validated against Minor mismatches (Bland-Altman line description, variables tooltip, bootstrap/seed enablement when only asymptotic-CI coefficients are selected) are all fixed in 3a997e0. |
F = (m-1)W/(1-W), df1 = n-1-2/m, df2 = df1(m-1) (Kendall & Babington Smith, 1939; Legendre, 2005); preferable for small samples. Requested in jasp-stats/jasp-issues#2151. Cross-validated against vegan::kendall.global. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Desktop applies the closest upgrade step AT OR ABOVE the file version (QMLComponents/modules/upgrader/upgrades.cpp: findClosestVersion), i.e. a step covers files saved with fromVersion or lower. 0.95.5 therefore missed files saved with 0.96.x (released v0.96.0, master's 0.96.4), losing their bootstrap count. Use the last version carrying the old option name. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Remaining correctness blockers
Additional behavioral issues
UI/documentation accuracySeveral newly added
The F-test comment at Verification and remaining test gaps
Given the weighted-Cohen result, factor handling, missing/effective-data failures, and invalid F-domain output, I think the PR should remain blocked pending another backend pass. |
- ratersInRows: encode factors onto union of levels BEFORE t(), rebuild factors after; rater columns named Rater1..m (t() stripped levels -> wrong order / all-NA parses / alphabetical weighted Cohen) - weighted Cohen: psych orders categories alphabetically; feed union level codes so declared ordinal order drives the weights - validate analyzed data, not raw rows: Fleiss needs >= 3 complete rows, Cohen wrapped in try (zero pairwise overlap), Kripp validates pairable observations / variation / finite metric data (all-NA gave alpha = 1) - >= 2 raters check for Cohen/Kripp/Kendall (one-rater row data fataled) - Kripp interval/ratio parse labels as numeric scores (codes manufactured equal distances); non-numeric labels or negative ratio data -> error - Fleiss: single-category data -> clear error (was malformed rows) - Kendall: constant rankings -> clear error (was NaN table); F test suppressed with footnote when df1 <= 0 (n=2, m=2 gave Inf/NaN) - bootstrap replicates ALWAYS tie-corrected (resampling introduces ties that distorted uncorrected CIs) + footnote - Cohen: pair labels from data columns (row mode concatenated all subject names), subject count requires >= 2 ratings, per-pair n column when data has missings; 2-level footnote fixed for numeric data - deps: Kripp table + setSeed/seed; variables.types on type-checked tables/state - tests for all of the above; regenerate T1 CI (corrected replicates) and weighted-Cohen expectations (union codes + n column) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- ICC: averaging gives k-version of SELECTED type, not always ICC(A,k) - SEM: minimumGroupSize applies to Thorndike/Feldt/ANOVA/Lord generalized - Bayesian: posterior plot shading is the probability region, CI is a separate error bar; point estimate affects tables only; retained samples = ceiling((samples-burnin)/thinning) - RA: placeholder info describes placeholder; Fleiss works with 2+ raters; F test comment: concern is few raters (Marozzi 2014), not subjects Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…pace Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
All addressed in d1296bb (backend + tests), f902d6f (info strings), 371ab32 (NEWS/whitespace): Correctness blockers
Behavioral
Info strings — all six corrected as described (ICC k-version of selected type; SEM group size = Thorndike/Feldt/ANOVA/Lord generalized; probability-region shading vs CI error bar; point estimate affects tables; retained samples = ceiling; placeholder/Fleiss texts). The F-test comment now points at small numbers of raters and cites Marozzi (2014) with the Legendre caveat. Housekeeping — NEWS gained the F test (Added) and a Fixed summary; the two trailing-whitespace lines in renv/activate.R are stripped. The >100-byte tar paths come from the long vdiffr snapshot names — renaming them means regenerating all snapshots, so I'd prefer to leave that for a dedicated cleanup (the warnings are benign for a non-CRAN module). Verification — full suite 129 passing locally (was 106; +23 from the new regression tests: ordered-factor weighted Cohen, row-mode labelled factors, zero overlap, all-missing Krippendorff, one rater, n=2/m=2, single-category Fleiss, constant rankings, tie-free uncorrected bootstrap, interval-scores, non-numeric interval labels). The two items that remain manual: live invalidation on a variable-type change, and the 0.96 → current .jasp migration (verified by hand earlier today). |
- union levels: numeric labels ordered by value, text labels merged preserving declared order (appearance order scrambled codes when a rater missed a middle category) - Fleiss: categories from labels via union levels, never unlist(dataset) (returns factor CODES on mixed factor/numeric columns); convert columns to character before irr/as.matrix (format() padded " 7" vs "7") - ratersInRows: mixed categorical/continuous columns -> validation error (one discrete column silently recoded numeric magnitudes to codes) - kripp deps: + variables.types (table + boot state), matching others - kendall: constant rankings detected via zero variance (uncorrected W returned a meaningless finite 0 that bypassed the NaN guard) - kendall CI policy: no bootstrap CI for the uncorrected W (resampling ties put the CI on the corrected scale -> estimate could fall outside its own CI); footnote explains - F test: NA + footnote at W = 1 (was Inf) - consolidation: .raterAgreementUnionCodes shared by handleData/Cohen/ kripp/kendall encoders; .raterAgreementAddCiColumns shared by all four CI blocks; kripp boot transposes once outside the loop; drop dead nCategories - tests: 4 new (mismatched level sets, mixed-type Fleiss, mixed row mode, constant uncorrected), CI-policy tests rewritten, regenerate weighted Cohen + Fleiss row order (union order change) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Ran an additional multi-angle self-review over the full PR diff; a033eac fixes what it found (all verified by running the code, not just reading it): Correctness
Kendall CI policy refinement: with replicates tie-corrected (as agreed for #10), an uncorrected point estimate could fall outside its own CI (constructed: W = 0.762 with CI [1,1]). Bootstrap CIs are therefore only offered for the tie-corrected coefficient; the uncorrected estimate gets a footnote explaining why. The F test now also shows NA with a footnote at W = 1 instead of ∞. Cleanup: shared Side effect worth noting: the new union ordering makes the weighted-Cohen expectations for the disjoint-category stress data (facGender/facExperim/debBinMiss20) land back on the original master values. Full suite: 138 passing. |
|
Follow-up review after the latest fixes, performed against exact PR head The latest commit resolves several earlier findings, including the corrected/uncorrected Kendall CI mismatch, numeric partial-level ordering, mixed row-mode handling, the Kripp dependency declarations, and the perfect-concordance F output. However, I can still reproduce the following issues. Correctness blockers
Secondary issues
Verification at this head: the full R 4.5.2 module suite passes ( |
…dation) 1. .raterAgreementUnionLevels: topological sort over the precedence constraints declared by every column, so partial textual level sets merge to one order independent of rater order; contradictory or underdetermined schemas set ordered = FALSE and weighted Cohen / ordinal Kripp refuse to run (flag survives the row-mode transpose, which rebuilds columns with a shared level set) 2. .kendallWRatings: back to per-column encoding -- Kendall ranks WITHIN raters, so the cross-rater union wrongly recoded numeric columns to appearance-order label codes when any column was discrete (regression introduced by the a033eac consolidation) 3. Kripp: validity determined by the effective coincidence data (only subjects rated >= 2 times); table requires a finite estimate; bootstrap replicates whose pairable ratings are constant are rejected rather than contributing a spurious alpha = 1 4. Cohen: each pair computed and validated on its own pairwise-complete data (>= 3 joint subjects, ratings vary, finite estimate); unusable pairs are excluded from the average with a note instead of blanking or fataling the table 5. Kendall bootstrap mirrors the table's rater-count and variance guards, so invalid input cannot run up to 10^7 replicates first 6. Cohen pair labels built from combn + colnames (psych's names broke on variable names containing spaces) Tests: 8 new (permutation invariance, ambiguous schema, mixed ordinal/scale Kendall invariance, non-varying coincidences, per-pair validation, spaced names, weighted+CI on a shared scale, bootstrap guard). Cohen rows now follow combn order (values unchanged); the legacy weighted test.csv block asserts the new ambiguity error, its weighted-value coverage moved to a valid shared-scale test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
All six addressed in dc2a127; each of your reproductions was run before and after. Correctness blockers
Secondary
Two deliberate test changes. The legacy Full suite: 163 passing locally. |
Property tests instead of hand-picked examples: every coefficient must be unchanged by operations that are no-ops on the ratings -- permuting raters, permuting subjects, relabelling categories (order-preserving for ordinal, any bijection for nominal), raters-in-rows vs -columns, strictly increasing per-rater transforms (Kendall), affine rescaling (Kripp interval). Includes a negative control (ratio alpha is scale- but not shift-invariant) and a guard that a coefficient which errored cannot pass vacuously. Fixtures deliberately include raters declaring only SUBSETS of the scale -- the case that makes the cross-rater level merge observable. Verified sensitive by mutation: reintroducing each historical bug makes the suite fail (greedy level merge -> 6 failures; Kendall via union codes -> 3; t() before encoding -> 1 failure + 1 error). Clean on current code. NEWS: tie-correction default and corrected-only bootstrap CI, the common ordinal scale requirement for weighted Cohen / ordinal alpha, per-pair Cohen validation and combn row order, Kripp coincidence validation, Fleiss SEs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
On your closing point — "the passing tests therefore do not currently cover these cases" — 3a168e4 adds a property-based invariance suite ( Every coefficient is asserted invariant under operations that are no-ops on the ratings:
Several fixtures deliberately give the raters only subsets of the scale (no rater observes every category) — the configuration that makes the cross-rater level merge observable, i.e. your finding 1. A guard also fails the property if a coefficient errored, so a table that failed to compute cannot pass vacuously. The suite is mutation-verified rather than merely green: reintroducing each historical bug makes it fail — greedy level merge → 6 failures, Kendall via the cross-rater union codes → 3 failures,
CI at |
|
Follow-up review against exact current PR head The latest two commits resolve all six issues from my preceding comment. The new topological merge also passed an independent comparison against 1,000 randomized brute-force ordering cases. Three additional correctness cases remain outside the new tests, however. 1. Numeric-looking ordinal labels bypass the declared order
An order-preserving relabeling of the same ordinal data from factor levels
The ratings and declared category order are identical; only the labels changed. Two raters declaring contradictory numeric orders are also silently accepted instead of receiving the new common-scale error. Factor levels should remain authoritative even when their labels look numeric. Numeric sorting should be limited to genuinely numeric columns for which no factor-level order exists. A regression test should use a non-monotonic but order-preserving numeric relabel such as 2. Pairwise weighted Cohen drops unused positions from the common scaleAt For a declared scale
Dropping the unused middle category 3. Row-mode Kendall ignores an ambiguous merged ordinal scale
With subject columns declaring partial constraints
In row mode the transposed rater columns need one common category order to rank subjects. Under the PR's existing policy, Kendall should reject this ambiguous scale, and the same guard must run before bootstrapping. A row-mode invariance/error test with partial ambiguous level sets would cover this path. Verification at this head:
The passing invariance suite currently uses numeric relabels whose numeric and declared orders coincide, full common factor levels for row/column equivalence, and no weighted-Cohen pair missing an interior scale category; therefore it does not exercise these three counterexamples. |
…n scale, row-mode Kendall ambiguity) - factor levels stay authoritative even when labels look numeric (union merge) - pairwise weighted Cohen keeps unused common-scale categories (psych levels=) - row-mode Kendall's W refuses an ambiguous merged ordinal scale Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
All three addressed in 250867e; each of your reproductions was checked before and after. Correctness blockers
Verification: full module suite passes (raterAgreement + the invariance suite, no regressions), 7 new regression tests added reproducing your three repro cases plus the negative/contradiction cases, |
adds Kendalls coefficient of concordance with the irr::kendall function.
also restructures the agreement analysis a bit
fixes jasp-stats/jasp-issues#2151