This vignette demonstrates how eq5dsuite supports the
full EQ-5D analytical workflow recommended by Devlin et al. (2020),
using the NHS Patient Reported Outcome Measures (PROMs) dataset bundled
with the package. The dataset includes patients undergoing hip
replacement, knee replacement, groin hernia repair, and varicose vein
surgery, who completed the EQ-5D-3L before and after their
procedure.
# The example dataset is bundled with the package
data(example_data)
head(example_data)
#> id time mo sc ua pd ad vas procedure year ageband gender
#> 1 86 Pre-op 2 2 3 3 1 85 Hip Replacement 2013/14 <NA> <NA>
#> 2 86 Post-op 1 1 1 1 1 88 Hip Replacement 2013/14 <NA> <NA>
#> 3 121 Pre-op 2 2 2 2 2 85 Hip Replacement 2013/14 <NA> <NA>
#> 4 121 Post-op 1 1 2 2 2 70 Hip Replacement 2013/14 <NA> <NA>
#> 5 123 Pre-op 2 2 2 2 1 35 Hip Replacement 2013/14 <NA> <NA>
#> 6 123 Post-op 2 2 2 2 2 65 Hip Replacement 2013/14 <NA> <NA>This example illustrates a typical single-group longitudinal workflow, addressing three practical questions: which problems do patients report before surgery, how does health change following the procedure, and how large is the overall health gain?
dim_names <- c("mo", "sc", "ua", "pd", "ad")
# Subset to hip replacement patients
hip_data <- example_data[example_data$procedure == "Hip Replacement", ]
# Add profile code and EQ-5D value
hip_data$profile_code <- toEQ5Dindex(
x = hip_data,
dim.names = dim_names
)
hip_data$value <- eq5d3l(
hip_data[, dim_names],
country = "GB",
dim.names = dim_names
)
#> Warning: 187 health state(s) are not valid EQ-5D-3L states and have been set to
#> NA: each of the five digits must be from 1 to 3 (e.g. 22292, 19111, 22291,
#> 99999, 91321).
# Pre-operative subset
hip_preop <- hip_data[hip_data$time == "Pre-op", ]eq5d_profile_level_summary(
df = hip_preop,
names_eq5d = dim_names,
eq5d_version = "3L"
)
#> Warning: 346 EQ-5D dimension observations are not a level the instrument allows
#> and have been set to NA (out of range: 346). Each level must be a whole number
#> from 1 to 3. Fractional values are not rounded: 1.9 is neither level 1 nor
#> level 2.
#> level n_All_mo freq_All_mo n_All_sc
#> 1 1 158 0.086956522 870
#> 2 2 1646 0.905888828 915
#> 3 3 13 0.007154651 23
#> 4 Total 1817 1.000000000 1808
#> 5 Number reporting any problems (levels 2+3) 1659 0.913043478 938
#> 6 Missing data 61 0.032481363 70
#> freq_All_sc n_All_ua freq_All_ua n_All_pd freq_All_pd n_All_ad freq_All_ad
#> 1 0.48119469 128 0.07067918 17 0.00942873 1107 0.61329640
#> 2 0.50608407 1360 0.75096632 1044 0.57903494 610 0.33795014
#> 3 0.01272124 323 0.17835450 742 0.41153633 88 0.04875346
#> 4 1.00000000 1811 1.00000000 1803 1.00000000 1805 1.00000000
#> 5 0.51880531 1683 0.92932082 1786 0.99057127 698 0.38670360
#> 6 0.03727370 67 0.03567625 75 0.03993610 73 0.03887114Most patients report problems with pain/discomfort, usual activities, and mobility, consistent with the profile expected in patients awaiting hip replacement.
eq5d_profile_top_states(
df = hip_preop,
names_eq5d = dim_names,
eq5d_version = "3L",
n = 5
)
#> Warning: 346 EQ-5D dimension observations are not a level the instrument allows
#> and have been set to NA (out of range: 346). Each level must be a whole number
#> from 1 to 3. Fractional values are not rounded: 1.9 is neither level 1 nor
#> level 2.
#> Health state Frequency Percentage Cumulative percentage
#> 1 21221 325 0.184031710 0.1840317
#> 2 22221 221 0.125141563 0.3091733
#> 3 22231 144 0.081540204 0.3907135
#> 4 22232 138 0.078142695 0.4688562
#> 5 22222 116 0.065685164 0.5345413
#> 6 ... NA NA NA
#> 7 33333 3 0.001698754 1.0000000
#> 8 Missing 112 0.059637913 NAHow much of the classification system does this sample actually use?
Shannon’s index H' measures that in bits, and
J' expresses it as a fraction of the maximum the instrument
allows, so it is comparable between samples and between instruments.
eq5d_profile_shannon(
df = hip_data,
names_eq5d = dim_names,
eq5d_version = "3L",
name_fu = "time",
levels_fu = c("Pre-op", "Post-op")
)
#> Warning: 535 EQ-5D dimension observations are not a level the instrument allows
#> and have been set to NA (out of range: 535). Each level must be a whole number
#> from 1 to 3. Fractional values are not rounded: 1.9 is neither level 1 nor
#> level 2.
#> dimension H_Pre-op Hmax_Pre-op J_Pre-op H_Post-op Hmax_Post-op J_Post-op
#> 1 mo 0.4865616 1.584963 0.3069862 0.9662515 1.584963 0.6096368
#> 2 sc 1.0851625 1.584963 0.6846613 0.7480963 1.584963 0.4719962
#> 3 ua 1.0240602 1.584963 0.6461100 1.1470151 1.584963 0.7236860
#> 4 pd 1.0470239 1.584963 0.6605985 1.1601272 1.584963 0.7319588
#> 5 ad 1.1740012 1.584963 0.7407123 0.7631921 1.584963 0.4815206
#> 6 Health state 4.3105740 7.924813 0.5439339 3.6577313 7.924813 0.4615543A dimension where nearly everyone gives the same answer carries
little information, and shows up as a low J'. The
Health state row applies the same measure to the whole
profile, against the 243 the EQ-5D-3L allows.
The Paretian Classification of Health Change (PCHC) classifies each
patient as Better, Worse, Mixed, or No Change between time points. All
plot functions in eq5dsuite return ggplot2 objects that can
be customised directly:
eq5d_profile_pchc_by_group_plot(
df = hip_data,
name_id = "id",
names_eq5d = dim_names,
name_fu = "time",
levels_fu = c("Pre-op", "Post-op")
)$p +
ggplot2::labs(
title = "PCHC: hip replacement patients",
x = NULL,
y = "Percentage of respondents"
) +
ggplot2::theme_minimal()
#> Warning: 535 EQ-5D dimension observations are not a level the instrument allows
#> and have been set to NA (out of range: 535). Each level must be a whole number
#> from 1 to 5. Fractional values are not rounded: 1.9 is neither level 1 nor
#> level 2.eq5d_profile_better_dimensions_by_group_plot(
df = hip_data,
name_id = "id",
names_eq5d = dim_names,
name_fu = "time",
levels_fu = c("Pre-op", "Post-op")
)$p +
ggplot2::theme_minimal()
#> Warning: 535 EQ-5D dimension observations are not a level the instrument allows
#> and have been set to NA (out of range: 535). Each level must be a whole number
#> from 1 to 5. Fractional values are not rounded: 1.9 is neither level 1 nor
#> level 2.The eq5d_utility_* functions analyse a column of EQ-5D
values rather than calculating one, so the values are added first. That
keeps the choice of value set in one visible place, and lets the same
analysis run on values that came from anywhere else — a crosswalk, the
NICE DSU mapping, or another package.
hip_data$value <- eq5d3l(
hip_data[, dim_names],
country = "GB",
dim.names = dim_names
)
#> Warning: 187 health state(s) are not valid EQ-5D-3L states and have been set to
#> NA: each of the five digits must be from 1 to 3 (e.g. 22292, 19111, 22291,
#> 99999, 91321).
eq5d_utility_summary(
df = hip_data,
name_utility = "value",
name_fu = "time",
levels_fu = c("Pre-op", "Post-op")
)
#> name Pre-op Post-op
#> 1 Mean 3.654281e-01 7.927837e-01
#> 2 Standard error 7.785437e-03 5.868664e-03
#> 3 Median 5.160000e-01 8.480001e-01
#> 4 Mode 6.910000e-01 1.000000e+00
#> 5 Standard deviation 3.271736e-01 2.491937e-01
#> 6 Kurtosis (non-excess) 1.642925e+00 6.093719e+00
#> 7 Skewness -2.961227e-01 -1.650594e+00
#> 8 Minimum -5.940000e-01 -3.490000e-01
#> 9 Maximum 1.000000e+00 1.000000e+00
#> 10 Range 1.594000e+00 1.349000e+00
#> 11 Observations 1.766000e+03 1.803000e+03
#> 12 Missing (n) 1.120000e+02 7.500000e+01
#> 13 Total sample 1.878000e+03 1.878000e+03
#> 14 Missing (%) 5.963791e+00 3.993610e+00eq5d_vas_summary(
df = hip_data,
name_vas = "vas",
name_fu = "time",
levels_fu = c("Pre-op", "Post-op")
)
#> Warning: 283 VAS observation(s) were coerced to NAs as they were not
#> interpretable as values in the range allowed by the EQ VAS (0 to 100).
#> name Pre-op Post-op
#> 1 Mean 65.5425849 77.0189521
#> 2 Standard error 0.5326207 0.4280138
#> 3 Median 70.0000000 80.0000000
#> 4 Mode 80.0000000 90.0000000
#> 5 Standard deviation 21.8244527 18.1287974
#> 6 Kurtosis (non-excess) 2.9313944 4.9233219
#> 7 Skewness -0.7415802 -1.3356073
#> 8 Minimum 0.0000000 0.0000000
#> 9 Maximum 100.0000000 100.0000000
#> 10 Range 100.0000000 100.0000000
#> 11 Observations 1679.0000000 1794.0000000
#> 12 Missing (n) 199.0000000 84.0000000
#> 13 Total sample 1878.0000000 1878.0000000
#> 14 Missing (%) 10.5963791 4.4728435This example demonstrates a cross-sectional group comparison using pre-operative data from knee replacement and groin hernia patients — two groups with very different levels of pre-operative health burden.
# Subset to two procedures, pre-operative only
procs <- c("Knee Replacement", "Groin Hernia")
comparison_data <- example_data[
example_data$procedure %in% procs &
example_data$time == "Pre-op", ]
# Add profile code and EQ-5D value
comparison_data$profile_code <- toEQ5Dindex(
x = comparison_data,
dim.names = dim_names
)
comparison_data$value <- eq5d3l(
comparison_data[, dim_names],
country = "GB",
dim.names = dim_names
)
#> Warning: 156 health state(s) are not valid EQ-5D-3L states and have been set to
#> NA: each of the five digits must be from 1 to 3 (e.g. 29292, 21291, 99999,
#> 21329, 21292).eq5d_profile_level_summary_by_group(
df = comparison_data,
names_eq5d = dim_names,
name_cat = "procedure",
eq5d_version = "3L"
)
#> No ordering of time supplied. The time variable will be factorised according to the order in the data frame.
#> Warning: 427 EQ-5D dimension observations are not a level the instrument allows
#> and have been set to NA (out of range: 427). Each level must be a whole number
#> from 1 to 3. Fractional values are not rounded: 1.9 is neither level 1 nor
#> level 2.
#> level n_Knee Replacement_mo
#> 1 1 133
#> 2 2 1789
#> 3 3 9
#> 4 Total 1931
#> 5 Number reporting any problems (levels 2+3) 1798
#> 6 Missing data 65
#> freq_Knee Replacement_mo n_Groin Hernia_mo freq_Groin Hernia_mo
#> 1 0.068876230 735 0.823068309
#> 2 0.926462973 158 0.176931691
#> 3 0.004660798 0 0.000000000
#> 4 1.000000000 893 1.000000000
#> 5 0.931123770 158 0.176931691
#> 6 0.032565130 6 0.006674082
#> n_Knee Replacement_sc freq_Knee Replacement_sc n_Groin Hernia_sc
#> 1 1353 0.702492212 853
#> 2 559 0.290238837 32
#> 3 14 0.007268951 3
#> 4 1926 1.000000000 888
#> 5 573 0.297507788 35
#> 6 70 0.035070140 11
#> freq_Groin Hernia_sc n_Knee Replacement_ua freq_Knee Replacement_ua
#> 1 0.960585586 164 0.08523909
#> 2 0.036036036 1518 0.78898129
#> 3 0.003378378 242 0.12577963
#> 4 1.000000000 1924 1.00000000
#> 5 0.039414414 1760 0.91476091
#> 6 0.012235818 72 0.03607214
#> n_Groin Hernia_ua freq_Groin Hernia_ua n_Knee Replacement_pd
#> 1 665 0.746352413 18
#> 2 209 0.234567901 1130
#> 3 17 0.019079686 756
#> 4 891 1.000000000 1904
#> 5 226 0.253647587 1886
#> 6 8 0.008898776 92
#> freq_Knee Replacement_pd n_Groin Hernia_pd freq_Groin Hernia_pd
#> 1 0.009453782 287 0.32283465
#> 2 0.593487395 560 0.62992126
#> 3 0.397058824 42 0.04724409
#> 4 1.000000000 889 1.00000000
#> 5 0.990546218 602 0.67716535
#> 6 0.046092184 10 0.01112347
#> n_Knee Replacement_ad freq_Knee Replacement_ad n_Groin Hernia_ad
#> 1 1205 0.63023013 759
#> 2 624 0.32635983 118
#> 3 83 0.04341004 13
#> 4 1912 1.00000000 890
#> 5 707 0.36976987 131
#> 6 84 0.04208417 9
#> freq_Groin Hernia_ad
#> 1 0.85280899
#> 2 0.13258427
#> 3 0.01460674
#> 4 1.00000000
#> 5 0.14719101
#> 6 0.01001112eq5d_utility_summary_by_group(
df = comparison_data,
name_utility = "value",
name_groupvar = "procedure"
)
#> name Groin Hernia Knee Replacement All groups
#> 1 Mean 7.877045e-01 4.039469e-01 5.262618e-01
#> 2 Standard error 6.945801e-03 7.163948e-03 6.355527e-03
#> 3 Median 7.960000e-01 5.870000e-01 6.910000e-01
#> 4 25th 7.270000e-01 8.799999e-02 1.590000e-01
#> 5 75th 1.000000e+00 6.910000e-01 7.600000e-01
#> 6 N 8.730000e+02 1.866000e+03 2.739000e+03
#> 7 Missing 2.600000e+01 1.300000e+02 1.560000e+02eq5d_utility_by_group_plot(
df = comparison_data,
name_utility = "value",
name_groupvar = "procedure"
)$p +
ggplot2::theme_minimal()
#> Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
#> ℹ Please use `linewidth` instead.
#> ℹ The deprecated feature was likely used in the eq5dsuite package.
#> Please report the issue at
#> <https://github.com/MathsInHealth/eq5dsuite-r/issues>.
#> This warning is displayed once per session.
#> Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
#> generated.The Level Sum Score (LSS) summarises overall severity as the sum of level scores across the five dimensions (range 5–15 for 3L, 5–25 for 5L). The plot below shows how EQ-5D values relate to LSS within each procedure group:
hernia_data <- comparison_data[
comparison_data$procedure == "Groin Hernia", ]
eq5d_profile_lss_utility_plot(
hernia_data,
names_eq5d = dim_names,
name_utility = "value",
eq5d_version = "3L"
)$p +
ggplot2::labs(
title = "Groin Hernia",
x = "Level Sum Score (LSS)",
y = "EQ-5D value"
) +
ggplot2::scale_x_continuous(limits = c(5, 15),
breaks = seq(5, 15, 2)) +
ggplot2::theme_minimal()
#> Warning: 44 EQ-5D dimension observations are not a level the instrument allows
#> and have been set to NA (out of range: 44). Each level must be a whole number
#> from 1 to 3. Fractional values are not rounded: 1.9 is neither level 1 nor
#> level 2.
#> Scale for x is already present.
#> Adding another scale for x, which will replace the existing scale.
#> Warning: Removed 2 rows containing missing values or values outside the scale range
#> (`geom_segment()`).knee_data <- comparison_data[
comparison_data$procedure == "Knee Replacement", ]
eq5d_profile_lss_utility_plot(
knee_data,
names_eq5d = dim_names,
name_utility = "value",
eq5d_version = "3L"
)$p +
ggplot2::labs(
title = "Knee Replacement",
x = "Level Sum Score (LSS)",
y = "EQ-5D value"
) +
ggplot2::scale_x_continuous(limits = c(5, 15),
breaks = seq(5, 15, 2)) +
ggplot2::theme_minimal()
#> Warning: 383 EQ-5D dimension observations are not a level the instrument allows
#> and have been set to NA (out of range: 383). Each level must be a whole number
#> from 1 to 3. Fractional values are not rounded: 1.9 is neither level 1 nor
#> level 2.
#> Scale for x is already present.
#> Adding another scale for x, which will replace the existing scale.
#> Warning: Removed 2 rows containing missing values or values outside the scale range
#> (`geom_segment()`).
#> Warning: Removed 2 rows containing missing values or values outside the scale range
#> (`geom_segment()`).vignette("crosswalk-methods") — when and how to use
crosswalk methodsvignette("custom-value-sets") — adding and managing
custom value setsvignette("update-value-sets") — keeping value sets up
to dateDevlin N, Parkin D, Janssen B (2020). Methods for Analysing and Reporting EQ-5D Data. Springer, Cham. https://doi.org/10.1007/978-3-030-47622-9