This vignette is for readers meeting these methods for the first time: graduate students developing a scale, and researchers who need to report content-validity evidence without first reading five primary sources.
It walks through what each part of the output means, what it does not mean, and how to describe the result in a manuscript. The other vignettes show how to run each workflow; this one shows how to read what comes back.
If you only remember one thing: every statistic here is evidence for a judgment you make, not a judgment the package makes for you.
sorts <- read.csv(
system.file("extdata", "sort_example.csv", package = "contentvalidR"),
stringsAsFactors = FALSE
)
fit_sort <- sort_validity(sorts)
fit_sort
#> contentvalidR item-sort analysis
#> --------------------------------
#> Items: 6 | Judges: 20 | Target constructs: 3
#> Test: Howard-Melloy exact target-count test (p0 = .50, alpha = .05)
#> Judges: naive, meaning drawn from the kind of people who will answer the
#> items.
#>
#> 4 of 6 items meet the exact target-assignment criterion.
#> Flagged for review: B2, C2
#>
#> Item-level evidence
#> item target decision judges Psa 95% CI Csv competitor p
#> A1 A Retain 18/20 .90 [.70, .97] .85 B; C < .001
#> A2 A Retain 15/20 .75 [.53, .89] .60 B .021
#> B1 B Retain 17/20 .85 [.64, .95] .75 A .001
#> B2 B Review 13/20 .65 [.43, .82] .40 A .132
#> C1 C Retain 18/20 .90 [.70, .97] .85 A; B < .001
#> C2 C Review 14/20 .70 [.48, .85] .50 B .058
#>
#> judges: assignments to the target construct, out of the judges who sorted the
#> item.
#> 95% intervals for proportions: Wilson score (the default). Newcombe (1998)
#> compared seven methods and recommends score intervals over the Wald interval.
#> An interval reflects how few ratings an item received, not whether the right
#> judges were chosen.
#>
#> Scale-level Colquitt benchmarks
#> target items mean Psa Psa level mean Csv Csv level
#> A 2 .82 Strong .72 Strong
#> B 2 .75 Moderate .57 Moderate
#> C 2 .80 Moderate .68 Strong
#> Benchmark set: Overall (not correlation-normed)
#>
#> Colquitt labels are empirical percentile norms derived from scale-level
#> averages, not universal cutoffs or automatic scale-retention rules. They
#> place a scale against published scales; Psa and Csv sit on different scales,
#> so their labels are not comparable with each other.
#>
#> 'Review' is not an automatic deletion decision. Use theory, construct-domain
#> coverage, item wording, and qualitative judge feedback alongside these
#> statistics.The printout opens with a one-line verdict (how many items met the criterion, and which were flagged), then one row per item. Working across the item table:
n_target and
n in results). Always read this before the
coefficients: an impressive Psa computed from four judges is not
impressive.p_value in results).Numbers follow the APA style rules (seventh edition, Section 6.36). A
statistic that cannot exceed 1, such as a proportion or a p
value, is printed without a leading zero (.90). One that can exceed 1
keeps it (0.57). A p value below .001 is printed as < .001.
The results table keeps every value at full precision.
The scale-level table adds Colquitt strength labels. These are percentile positions relative to scales published in the literature, not absolute judgments, and they are the most frequently misreported part of this output.
Here is the misreading to guard against, using construct ratings:
ratings <- read.csv(
system.file("extdata", "rating_example.csv", package = "contentvalidR"),
stringsAsFactors = FALSE
)
fit_rating <- rating_validity(ratings)
fit_rating$scale_summary[, c("target", "mean_htc", "htc_strength",
"mean_htd", "htd_strength")]
#> target mean_htc htc_strength mean_htd htd_strength
#> 1 A 0.8333333 Weak 0.4375 Very Strong
#> 2 B 0.8333333 Weak 0.4375 Very Strong
#> 3 C 0.8333333 Weak 0.4375 Very StrongAn HTC of about .83 is labeled Weak, while an HTD of
about .44 in the same row is labeled Very Strong. Read as
raw numbers this looks backwards, and it is a common source of
confusion.
The two indices are not on the same scale and their numbers are not comparable:
Compare each index against its own benchmark. Never compare an HTC number with an HTD number, and never treat a benchmark label as a cutoff for retention.
colquitt_benchmarks("htc")
#> Benchmarks for HTC (Colquitt et al., 2019): Overall (not correlation-normed)
#>
#> band percentile minimum
#> Very Strong 80th-99th .91
#> Strong 60th-79th .87
#> Moderate 40th-59th .84
#> Weak 20th-39th .60
#> Lack of 0th-19th none
#>
#> A scale-level mean at or above a band's minimum falls in that band. The bands
#> are percentiles of published scales, not validity cutoffs.
colquitt_benchmarks("htd")
#> Benchmarks for HTD (Colquitt et al., 2019): Overall (not correlation-normed)
#>
#> band percentile minimum
#> Very Strong 80th-99th .35
#> Strong 60th-79th .27
#> Moderate 40th-59th .18
#> Weak 20th-39th .04
#> Lack of 0th-19th none
#>
#> A scale-level mean at or above a band's minimum falls in that band. The bands
#> are percentiles of published scales, not validity cutoffs.relevance <- read.csv(
system.file("extdata", "expert_relevance_example.csv", package = "contentvalidR"),
stringsAsFactors = FALSE
)
panel <- as.matrix(relevance[, setdiff(names(relevance), "expert")])
fit_expert <- expert_validity(panel, mode = "relevance", lo = 1, hi = 4)
fit_expert$results[, c("item", "N", "V", "I_CVI", "I_CVI_low", "I_CVI_high",
"kappa_mod", "recommendation")]
#> item N V I_CVI I_CVI_low I_CVI_high kappa_mod recommendation
#> 1 Item1 8 1.0000000 1.00 0.67559244 1.0000000 1.0000000 Strong support
#> 2 Item2 8 0.9166667 1.00 0.67559244 1.0000000 1.0000000 Strong support
#> 3 Item3 8 0.8333333 1.00 0.67559244 1.0000000 1.0000000 Strong support
#> 4 Item4 8 0.5833333 0.75 0.40927543 0.9285208 0.7192982 Review
#> 5 Item5 8 0.4166667 0.25 0.07147921 0.5907246 0.1578947 ReviewI_CVI is the proportion of experts calling the item
relevant. kappa_mod corrects that for chance agreement, and
the gap between them matters most with small panels, where several
experts can agree by luck alone. Aiken’s V uses the whole
rating scale rather than a relevance cut, so it distinguishes items that
I_CVI rates identically.
Note that the I-CVI criterion depends on panel size. It follows Lynn
(1986): with three to five experts all must agree, from six one may
disagree, and from nine two may. cvi_criterion shows the
proportion that applies to each item’s panel, so 7 of 9 appears as .778.
An item can therefore change status simply because a judge was added or
dropped.
I_CVI_low and I_CVI_high bound the I-CVI.
With eight experts, an item that every expert rated relevant still has a
lower limit well below 1: a panel that size cannot rule out a noticeably
lower relevance rate. Read the interval before treating an I-CVI as
settled, and report it alongside the point estimate.
The interval method is a choice. The Wilson score interval is the default, following Newcombe (1998), and alternatives are available when a study needs to match earlier work:
exact <- expert_validity(panel, mode = "relevance", lo = 1, hi = 4,
proportion_ci = "exact")
exact$results[, c("item", "I_CVI", "I_CVI_low", "I_CVI_high")]
#> item I_CVI I_CVI_low I_CVI_high
#> 1 Item1 1.00 0.63058335 1.0000000
#> 2 Item2 1.00 0.63058335 1.0000000
#> 3 Item3 1.00 0.63058335 1.0000000
#> 4 Item4 0.75 0.34914421 0.9681460
#> 5 Item5 0.25 0.03185403 0.6508558The exact (Clopper-Pearson) interval is conservative, so its limits sit further apart. The printed output always names the method that produced the interval.
Relevance mode also reports one agreement coefficient for the whole
panel, in scale_summary as agreement,
agreement_low, and agreement_high. The full
result, with its explanation, is in details$agreement, and
panel_agreement() produces the same result directly:
panel_agreement(panel, seed = 1)
#> contentvalidR panel agreement
#> -----------------------------
#> Items rated by two or more raters: 5 | Raters: 8
#> Krippendorff's alpha (ordinal) = .69, 95% CI [.07, .86]
#> Identical rating pairs: 62.9%
#>
#> Alpha compares the disagreement observed within items with the disagreement
#> expected if these same ratings were assigned to items at random: 1 means
#> perfect agreement and 0 means agreement no better than chance. Alpha falls
#> when ratings cluster on a few values, because little disagreement is then
#> expected by chance. A high share of identical rating pairs alongside a low
#> alpha reflects that clustering, which is common when nearly every item is
#> rated relevant, and is not by itself evidence of a poor panel.
#>
#> Krippendorff's alpha is the default because it handles ordinal ratings and
#> missing ratings (Zapf et al., 2016). It is a general reliability coefficient;
#> no publication applying it specifically to content-validity panels was found.
#>
#> The interval resamples items with all of their ratings, following Zapf et al.
#> (2016), and varies slightly between runs unless `seed` is set.
#>
#> Panel agreement describes how consistently raters rated these items. It does
#> not show that the items are relevant or that the domain is covered.Read two numbers together: the coefficient and the share of identical rating pairs. Krippendorff’s alpha, the default, can be low on a panel that agrees closely when nearly every rating is the same value, because chance then predicts very little disagreement. A low alpha next to a high share of identical pairs reflects that clustering. Agreement describes the raters, not the items: a consistent panel can still consistently rate an item as irrelevant.
judge_validity() asks a different question: do your
conclusions depend on these particular judges?
judge_ratings <- rbind(
c(4, 4, 4, 3, 2, 2), c(4, 4, 3, 4, 2, 1), c(4, 3, 4, 4, 1, 2),
c(3, 4, 4, 4, 2, 2), c(4, 4, 4, 4, 2, 1), c(4, 3, 4, 3, 1, 2),
c(4, 4, 3, 4, 2, 2), c(2, 2, 2, 2, 1, 1)
)
dimnames(judge_ratings) <- list(paste0("Judge", 1:8), paste0("Item", 1:6))
fit_judge <- judge_validity(judge_ratings, lo = 1, hi = 4)
fit_judge$results[, c("judge", "mean_rating", "severity_raw",
"differentiation", "n_items_flipped", "recommendation")]
#> judge mean_rating severity_raw differentiation n_items_flipped
#> 1 Judge1 3.166667 -0.2708333 0.9136465 0
#> 2 Judge2 3.000000 -0.1041667 1.1754383 0
#> 3 Judge3 3.000000 -0.1041667 1.1754383 0
#> 4 Judge4 3.166667 -0.2708333 0.9136465 0
#> 5 Judge5 3.166667 -0.2708333 1.2351428 0
#> 6 Judge6 2.833333 0.0625000 1.0863535 0
#> 7 Judge7 3.166667 -0.2708333 0.9136465 0
#> 8 Judge8 1.666667 1.2291667 0.4798707 0
#> recommendation
#> 1 Typical
#> 2 Typical
#> 3 Typical
#> 4 Typical
#> 5 Typical
#> 6 Typical
#> 7 Typical
#> 8 Severeseverity_raw is signed so that positive means
harsher: the judge rates lower than the panel.
differentiation near 1 means the judge used the scale about
as widely as everyone else. n_items_flipped is the
influence diagnostic: how many items would change review status if this
judge were removed.
A judge flagged here is not a judge to delete. A dissenting expert may be the one reading the construct definition correctly. The flag tells you a conclusion rests on one person’s ratings, which is worth knowing before you write it up.
The panel-level dependability coefficient answers a planning question:
summary(fit_judge)$gtheory$judges_needed
#> target n_judges_relative n_judges_absolute
#> 1 0.7 1 2
#> 2 0.8 2 2
#> 3 0.9 3 5That table reports how many judges a target coefficient would need.
Where it returns NA, no realistic panel reaches that
target, which usually means the judges barely distinguished the
items.
assignments <- data.frame(
item = paste0("I", 1:7),
construct = c("Autonomy", "Autonomy", "Autonomy", "Autonomy",
"Competence", "Competence", "Relatedness"),
stringsAsFactors = FALSE
)
fit_domain <- domain_validity(
assignments,
cell_col = "construct",
domain = c("Autonomy", "Competence", "Relatedness", "Belonging")
)
fit_domain$results[, c("cell", "n_items", "share", "recommendation")]
#> cell n_items share recommendation
#> 1 Autonomy 4 0.5714286 Over-represented
#> 2 Competence 2 0.2857143 Covered
#> 3 Relatedness 1 0.1428571 Thinly covered
#> 4 Belonging 0 0.0000000 Not coveredThe Belonging row is the point of this analysis. No item
addresses that cell, and no item-level index could ever have
told you, because relevance statistics can only describe items
that exist. A perfect I-CVI on every item you wrote says nothing about
the facet you forgot.
This only works because the full cell list was supplied through
domain. Omit it and the analysis can only describe the
cells that already contain items, and the output says so rather than
implying complete coverage.
“Review means delete.” It does not. It means look closer. Deleting every flagged item optimizes a statistic at the cost of the content domain, which is the opposite of content validity.
“Strong means good.” Benchmark labels are percentile
positions against published scales. Strong means typical of
published work, not that the item is fit for your purpose.
“One index is enough.” No single coefficient establishes content validity. These are components of an argument that also rests on construct definitions, domain coverage, cognitive interviewing, and expert comment.
“The numbers are comparable.” HTC against HTD, Psa against Csv, or one index against the benchmark belonging to a different index: these comparisons are not meaningful.
“A high coefficient means the domain is covered.”
Relevance and coverage are different questions. Only
domain_validity() addresses coverage, and only when you
give it the full blueprint.
“More judges always helps.” More judges narrows
intervals, but it can also change a criterion: the I-CVI guideline
shifts at six experts. Check judges_needed rather than
assuming.
A defensible sentence reports the estimate, its precision, the decision rule you applied, and what you concluded, without implying the statistic made the decision:
Six items were sorted by 20 naive judges. Four items met the Howard-Melloy exact target-assignment criterion (p < .05). Items B2 and C2 did not (Psa = .65 and .70), and in both cases the competing construct was the adjacent scale. Rather than removing them, we revised their wording to sharpen the distinction from that scale and re-sorted.
Report what you cannot establish as well:
These analyses address definitional correspondence and distinctiveness. They do not establish that the item set covers the construct domain; coverage was assessed separately against the blueprint.
settings and design hold everything a
reader needs to reproduce the decision rules, so report them rather than
only the coefficients:
Printed output includes a key defining each column. Once the terms are familiar:
The definitions remain available at any time:
American Psychological Association. (2020). Publication manual of the American Psychological Association (7th ed.). https://doi.org/10.1037/0000165-000
Lynn, M. R. (1986). Determination and quantification of content validity. Nursing Research, 35(6), 382–385. https://doi.org/10.1097/00006199-198611000-00017
Newcombe, R. G. (1998). Two-sided confidence intervals for the single proportion: Comparison of seven methods. Statistics in Medicine, 17(8), 857–872. https://doi.org/10/cpchjg