The HiTOP-BR instrument has 45 items and yields 8 scale scores. To
demonstrate the ability of the package to calculate these scale scores,
we can use real example data (n=411) that was collected at the
University of Kansas (KU) by Girard & Gray in 2024–2025. This data
is stored in the package under the name ku_hitopbr.
First, we load the package into memory using the
library() function. If this doesn’t work, make sure you
installed the package properly (see the README on GitHub).
Next, we can load the example dataset from the package using the
data() function. It is a large tibble that contains a
participant column with a unique identifier for each
participant, a biosex column indicating whether each
participant is “female” or “male”, and then 45 columns numbered
hbr_01 to hbr_45 containing each participant’s
rating on each item of the HiTOP-BR (on a numerical scale from 1 to
4).
data("ku_hitopbr")
ku_hitopbr
#> # A tibble: 411 × 47
#> participant biosex hbr_01 hbr_02 hbr_03 hbr_04 hbr_05 hbr_06 hbr_07 hbr_08
#> <chr> <fct> <int> <int> <int> <int> <int> <int> <int> <int>
#> 1 P001 male 1 1 1 1 2 1 1 1
#> 2 P002 male 1 1 1 1 2 2 2 1
#> 3 P003 male 1 2 1 2 3 4 3 3
#> 4 P004 male 1 1 1 1 2 1 1 1
#> 5 P005 male 1 4 1 1 3 1 1 1
#> 6 P006 female 1 1 1 1 1 1 1 1
#> 7 P007 female 1 1 1 1 1 1 1 1
#> 8 P008 male 2 1 1 1 3 1 3 2
#> 9 P009 female 1 1 1 1 3 1 1 1
#> 10 P010 female 1 1 1 1 2 1 1 1
#> # ℹ 401 more rows
#> # ℹ 37 more variables: hbr_09 <int>, hbr_10 <int>, hbr_11 <int>, hbr_12 <int>,
#> # hbr_13 <int>, hbr_14 <int>, hbr_15 <int>, hbr_16 <int>, hbr_17 <int>,
#> # hbr_18 <int>, hbr_19 <int>, hbr_20 <int>, hbr_21 <int>, hbr_22 <int>,
#> # hbr_23 <int>, hbr_24 <int>, hbr_25 <int>, hbr_26 <int>, hbr_27 <int>,
#> # hbr_28 <int>, hbr_29 <int>, hbr_30 <int>, hbr_31 <int>, hbr_32 <int>,
#> # hbr_33 <int>, hbr_34 <int>, hbr_35 <int>, hbr_36 <int>, hbr_37 <int>, …Basic Scoring
To turn these item-level ratings into mean scores on the 8 scales, we
can use the score_hitopbr() function. It needs to know what
object contains the data and which columns contain the item-level data.
There are several ways we can specify the items. First, we can provide
the column numbers and use the : shortcut. In this tibble,
the items are from column 3 to column 47 so we can use
items = 3:47. I am going to also set
append = FALSE so that you can quickly see the scale
scores.
scores <- score_hitopbr(
data = ku_hitopbr,
items = 3:47,
append = FALSE
)
scores
#> # A tibble: 411 × 8
#> hbr_antagonism hbr_detachment hbr_disinhibition hbr_internalizing
#> <dbl> <dbl> <dbl> <dbl>
#> 1 1.44 1.4 1.33 1.12
#> 2 1.33 1.4 1.33 2.25
#> 3 2.11 2.4 2.33 2.75
#> 4 1.11 1.2 1.33 1.12
#> 5 2.44 1 2.22 1.88
#> 6 1 1.2 1.22 1.12
#> 7 1 1 1 1
#> 8 1.67 1.6 1.33 1.75
#> 9 1.44 1.4 1.56 1.12
#> 10 1.33 1 1 1.25
#> # ℹ 401 more rows
#> # ℹ 4 more variables: hbr_somatoform <dbl>, hbr_thoughtDisorder <dbl>,
#> # hbr_externalizing <dbl>, hbr_pFactor <dbl>Appending
If I had instead set append = TRUE (or left it off, as
that is the default), we would get back the ku_hitopbr
tibble with the scale scores added to the end as extra columns. Notice
below how we now have 55 columns instead of 47.
scores <- score_hitopbr(
data = ku_hitopbr,
items = 3:47
)
scores
#> # A tibble: 411 × 55
#> participant biosex hbr_01 hbr_02 hbr_03 hbr_04 hbr_05 hbr_06 hbr_07 hbr_08
#> <chr> <fct> <int> <int> <int> <int> <int> <int> <int> <int>
#> 1 P001 male 1 1 1 1 2 1 1 1
#> 2 P002 male 1 1 1 1 2 2 2 1
#> 3 P003 male 1 2 1 2 3 4 3 3
#> 4 P004 male 1 1 1 1 2 1 1 1
#> 5 P005 male 1 4 1 1 3 1 1 1
#> 6 P006 female 1 1 1 1 1 1 1 1
#> 7 P007 female 1 1 1 1 1 1 1 1
#> 8 P008 male 2 1 1 1 3 1 3 2
#> 9 P009 female 1 1 1 1 3 1 1 1
#> 10 P010 female 1 1 1 1 2 1 1 1
#> # ℹ 401 more rows
#> # ℹ 45 more variables: hbr_09 <int>, hbr_10 <int>, hbr_11 <int>, hbr_12 <int>,
#> # hbr_13 <int>, hbr_14 <int>, hbr_15 <int>, hbr_16 <int>, hbr_17 <int>,
#> # hbr_18 <int>, hbr_19 <int>, hbr_20 <int>, hbr_21 <int>, hbr_22 <int>,
#> # hbr_23 <int>, hbr_24 <int>, hbr_25 <int>, hbr_26 <int>, hbr_27 <int>,
#> # hbr_28 <int>, hbr_29 <int>, hbr_30 <int>, hbr_31 <int>, hbr_32 <int>,
#> # hbr_33 <int>, hbr_34 <int>, hbr_35 <int>, hbr_36 <int>, hbr_37 <int>, …Items as Strings
Alternatively, we could provide the item column names as a character
string. Typing out all 45 item names would be a hassle, but luckily this
dataset named them consistently so we can build the names automatically
using sprintf(). If we use the “hbr_%02d” format and apply
that across the numbers 1 to 45, that will create the zero-padded column
names we need. The same pattern names the items in the package’s other
example dataset (sim_hitopbr) and in data collected through
its Qualtrics and REDCap exports, so this one expression selects the
items in all of them.
scores <- score_hitopbr(
data = ku_hitopbr,
items = sprintf("hbr_%02d", 1:45),
append = FALSE
)
scores
#> # A tibble: 411 × 8
#> hbr_antagonism hbr_detachment hbr_disinhibition hbr_internalizing
#> <dbl> <dbl> <dbl> <dbl>
#> 1 1.44 1.4 1.33 1.12
#> 2 1.33 1.4 1.33 2.25
#> 3 2.11 2.4 2.33 2.75
#> 4 1.11 1.2 1.33 1.12
#> 5 2.44 1 2.22 1.88
#> 6 1 1.2 1.22 1.12
#> 7 1 1 1 1
#> 8 1.67 1.6 1.33 1.75
#> 9 1.44 1.4 1.56 1.12
#> 10 1.33 1 1 1.25
#> # ℹ 401 more rows
#> # ℹ 4 more variables: hbr_somatoform <dbl>, hbr_thoughtDisorder <dbl>,
#> # hbr_externalizing <dbl>, hbr_pFactor <dbl>Scale Prefixes
Also note that each scale column has the prefix “hbr_” in its name.
You can change the prefix (e.g., setting it to "hitopbr_")
or even turn it off (e.g., setting it to "") using the
prefix argument.
scores <- score_hitopbr(
data = ku_hitopbr,
items = sprintf("hbr_%02d", 1:45),
prefix = "",
append = FALSE
)
scores
#> # A tibble: 411 × 8
#> antagonism detachment disinhibition internalizing somatoform thoughtDisorder
#> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1.44 1.4 1.33 1.12 1.25 1
#> 2 1.33 1.4 1.33 2.25 1.25 1
#> 3 2.11 2.4 2.33 2.75 2.88 1.83
#> 4 1.11 1.2 1.33 1.12 1.38 1
#> 5 2.44 1 2.22 1.88 1.25 1
#> 6 1 1.2 1.22 1.12 1 1
#> 7 1 1 1 1 1 1
#> 8 1.67 1.6 1.33 1.75 1.75 1.17
#> 9 1.44 1.4 1.56 1.12 1.38 1
#> 10 1.33 1 1 1.25 1 1
#> # ℹ 401 more rows
#> # ℹ 2 more variables: externalizing <dbl>, pFactor <dbl>Simple Standard Errors (deprecated)
The calc_se argument is deprecated. It,
and the _se columns it adds, will be removed in a future
release, and a call that passes calc_se = TRUE now warns.
Use interval_hitopbr() instead, shown under Confidence Intervals below.
What the argument computes, while it lasts: the SD of the items the respondent actually answered divided by the square root of how many of those items they answered. Each one summarizes how much a respondent’s answers varied within a scale; it is not an estimate of how precisely the scale measures the underlying trait, so it does not give a confidence interval for a respondent’s true score. That is what replaces it: an interval, from the reliability of the scale rather than from one respondent’s spread of answers.
Confidence Intervals
A scale score is measured with error, so it is worth reporting a
range rather than a single number. interval_hitopbr()
returns three columns per scale: _est, an estimate of the
respondent’s true score, and _lo and _hi, the
bounds of a confidence interval around it.
scored <- score_hitopbr(
data = ku_hitopbr,
items = sprintf("hbr_%02d", 1:45),
append = FALSE
)
interval_hitopbr(
data = scored,
scores = c("hbr_detachment", "hbr_pFactor"),
append = FALSE
)
#> # A tibble: 411 × 6
#> hbr_detachment_est hbr_detachment_lo hbr_detachment_hi hbr_pFactor_est
#> <dbl> <dbl> <dbl> <dbl>
#> 1 1.45 0.808 2.10 1.44
#> 2 1.45 0.808 2.10 1.44
#> 3 2.38 1.74 3.03 2.36
#> 4 1.27 0.622 1.91 1.13
#> 5 1.08 0.437 1.73 1.51
#> 6 1.27 0.622 1.91 1.28
#> 7 1.08 0.437 1.73 1.05
#> 8 1.64 0.993 2.28 1.51
#> 9 1.45 0.808 2.10 1.28
#> 10 1.08 0.437 1.73 1.13
#> # ℹ 401 more rows
#> # ℹ 2 more variables: hbr_pFactor_lo <dbl>, hbr_pFactor_hi <dbl>The estimate is not the observed score. It is the observed score pulled toward the reference group’s mean, because with imperfect measurement a true score tends to lie nearer the mean than the observed score does – the less reliable the scale, the further it is pulled. The method is the regression approach with scale correction from Schmukle (2026), which puts the estimate back on the same metric as the observed score so the two can be read against each other.
The width comes from the scale’s reliability and the reference
group’s standard deviation, so it is the same for every respondent on a
given scale and it narrows as reliability rises. Widen or narrow the
interval with level:
interval_hitopbr(
data = scored,
scores = "hbr_detachment",
level = 0.80,
append = FALSE
)
#> # A tibble: 411 × 3
#> hbr_detachment_est hbr_detachment_lo hbr_detachment_hi
#> <dbl> <dbl> <dbl>
#> 1 1.45 1.03 1.87
#> 2 1.45 1.03 1.87
#> 3 2.38 1.96 2.80
#> 4 1.27 0.846 1.69
#> 5 1.08 0.660 1.50
#> 6 1.27 0.846 1.69
#> 7 1.08 0.660 1.50
#> 8 1.64 1.22 2.06
#> 9 1.45 1.03 1.87
#> 10 1.08 0.660 1.50
#> # ℹ 401 more rowsWhat the reference group is
The mean, standard deviation and reliability behind every number
above are shipped as hitopbr_devstats, transcribed from the
Superspectra and Spectra block of Table 1 of the HiTOP-SR introduction
paper.
hitopbr_devstats
#> # A tibble: 8 × 8
#> Scale camelCase type nItems reliability reliabilityType mean sd
#> <chr> <chr> <chr> <int> <dbl> <chr> <dbl> <dbl>
#> 1 Antagonism antagoni… scale 9 0.82 alpha 1.42 0.45
#> 2 Detachment detachme… scale 5 0.86 alpha 2.13 0.88
#> 3 Disinhibition disinhib… scale 9 0.86 alpha 1.65 0.6
#> 4 Externalizing external… scale 10 0.83 alpha 1.54 0.49
#> 5 Internalizing internal… scale 8 0.9 alpha 1.85 0.77
#> 6 p-Factor pFactor scale 12 0.86 alpha 1.68 0.55
#> 7 Somatoform somatofo… scale 8 0.88 alpha 1.82 0.71
#> 8 Thought Disord… thoughtD… scale 6 0.85 alpha 1.26 0.46That reference group is the paper’s Development Sample 2, N = 780 Prolific Academic participants stratified by sex and age to approximate a community-representative United States population. It is a development sample, and not a community norm. No census weighting was applied and the paper publishes no raw-score to T-score table. So an interval here says where a score sits relative to the sample the instrument was developed on; it does not say what percentile that score occupies in any population.
Three further limits are worth knowing before you report one of these intervals.
- The interval is symmetric and the same width for every respondent on
a scale, which is what classical test theory implies, and it is
not clipped to the 1-4 response range. Every HiTOP-BR
scale is skewed enough for this to show: on all eight, a score at the
response floor of 1 returns a lower bound below
- The coverage the method demonstrates is across a population of
respondents: about
levelof the intervals contain the true score when respondents are drawn from the reference distribution. It is not a guarantee for any one respondent. - The eight scales overlap. Externalizing and p-Factor are drawn from the same items as the six spectrum scales rather than added to them, so a respondent contributes the same answers to several of these intervals; read them as eight views of one response set rather than eight independent measurements.
Scale Reliability
As we compute scale scores, we can also estimate their inter-item reliability using Cronbach’s α (alpha) or McDonald’s ω (omega total). α is fast and widely used, but it assumes tau-equivalence (all items load equally on a single factor); violations can make α under- or over-estimate reliability. ω is based on a congeneric single-factor model, allowing items to have different loadings and error variances; it typically provides a more accurate reliability estimate for unit-weighted sums. Both assume the scale is essentially unidimensional; α and ω coincide when tau-equivalence holds.
We estimate reliability with the reliability_hitopbr()
function, which returns a tibble with one row per scale: its printed
name (Scale), the stem that names its column in the scored
output (camelCase), the number of items
(nItems), and the requested coefficients. By default it
computes both alpha and omega; for the latter,
we will need the lavaan package installed (set
omega = FALSE to skip it).
reliability_hitopbr(
data = ku_hitopbr,
items = sprintf("hbr_%02d", 1:45)
)
#> # A tibble: 8 × 5
#> Scale camelCase nItems alpha omega
#> <chr> <chr> <int> <dbl> <dbl>
#> 1 Antagonism antagonism 9 0.805 0.811
#> 2 Detachment detachment 5 0.801 0.792
#> 3 Disinhibition disinhibition 9 0.807 0.810
#> 4 Internalizing internalizing 8 0.834 0.836
#> 5 Somatoform somatoform 8 0.825 0.832
#> 6 Thought Disorder thoughtDisorder 6 0.731 0.739
#> 7 Externalizing externalizing 10 0.817 0.818
#> 8 p-Factor pFactor 12 0.804 0.811Labelling Columns
Column names like hbr_01 and hbr_antagonism
are compact but say nothing about what they hold. The
label_hitopbr() function attaches a label
attribute to each column it recognizes: the literal item text for item
columns, and the printed scale name for scored columns. Tools that read
that attribute — data viewers and reporting packages — can then show the
wording instead of the column name, so the labels travel with the data
rather than living in a separate lookup table.
Which columns it recognizes depends on prefix, which
must match how your item columns are actually named. The default,
"hbr_", is how both example datasets and the package’s
REDCap export name them (hbr_01 to hbr_45), so
sim_hitopbr needs no prefix; data collected
through the package’s Qualtrics export is named HBR_01 to
HBR_45 and would pass prefix = "HBR_". The
number must be zero-padded to two digits: columns carrying the prefix
and a number without the leading zero are not labelled, and the function
warns and names them.
data("sim_hitopbr")
labelled_items <- label_hitopbr(sim_hitopbr, target = "items")
attr(labelled_items$hbr_01, "label")
#> [1] "I found it easy to deceive others."Set target = "scales" to label the output of
score_hitopbr() instead. Here prefix is the
one the scoring function put on its output columns. Both functions
default to "hbr_", so a scored frame built with default
settings labels with none given:
sim_scores <- score_hitopbr(sim_hitopbr, items = 1:45, append = FALSE)
labelled_scales <- label_hitopbr(sim_scores, target = "scales")
attr(labelled_scales$hbr_antagonism, "label")
#> [1] "Antagonism"Columns the function does not recognize are returned untouched, and if no column matches the prefix at all it says so with a warning rather than silently returning the data unchanged.
