# A Few Notes on Labels

#### Ethan Heinzen

# Introduction

The `arsenal` package relies somewhat heavily on variable labels to make output more “pretty”. A `label` here is understood to be a single character string with “pretty” text (i.e., not an “ugly” variable name). Three of the main `arsenal` function use labels in their `summary()` output. There are several ways to set these labels.

We’ll use the `mockstudy` dataset for all examples here:

    library(arsenal)
    data(mockstudy)
    library(magrittr)

    ## Warning: package 'magrittr' was built under R version 4.0.2

    # for 'freqlist' examples
    tab.ex <- table(mockstudy[c("arm", "sex", "mdquality.s")], useNA="ifany")

# Examples

## Set labels in the function call

The `summary()` method for `tableby()`, `modelsum()`, and `freqlist()` objects contains a `labelTranslations =` argument to specify labels in the function call. Note that the `freqlist()` function matches labels in order, whereas the other two match labels by name. The labels can be input as a list or a character vector.

    summary(freqlist(tab.ex),
            labelTranslations = c(arm = "Treatment Arm", sex = "Gender", mdquality.s = "LASA QOL"))

Treatment Arm | Gender | LASA QOL | Freq | Cumulative Freq | Percent | Cumulative Percent
--- | --- | --- | --- | --- | --- | ---
A: IFL | Male | 0 | 29 | 29 | 1.93 | 1.93
|  | 1 | 214 | 243 | 14.28 | 16.21
|  | NA | 34 | 277 | 2.27 | 18.48
| Female | 0 | 12 | 289 | 0.80 | 19.28
|  | 1 | 118 | 407 | 7.87 | 27.15
|  | NA | 21 | 428 | 1.40 | 28.55
F: FOLFOX | Male | 0 | 31 | 459 | 2.07 | 30.62
|  | 1 | 285 | 744 | 19.01 | 49.63
|  | NA | 95 | 839 | 6.34 | 55.97
| Female | 0 | 21 | 860 | 1.40 | 57.37
|  | 1 | 198 | 1058 | 13.21 | 70.58
|  | NA | 61 | 1119 | 4.07 | 74.65
G: IROX | Male | 0 | 17 | 1136 | 1.13 | 75.78
|  | 1 | 187 | 1323 | 12.47 | 88.26
|  | NA | 24 | 1347 | 1.60 | 89.86
| Female | 0 | 14 | 1361 | 0.93 | 90.79
|  | 1 | 121 | 1482 | 8.07 | 98.87
|  | NA | 17 | 1499 | 1.13 | 100.00

    summary(tableby(arm ~ sex + age, data = mockstudy),
            labelTranslations = c(sex = "SEX", age = "Age, yrs"))

| A: IFL (N=428) | F: FOLFOX (N=691) | G: IROX (N=380) | Total (N=1499) | p value
--- | --- | --- | --- | --- | ---
SEX |  |  |  |  | 0.190
Male | 277 (64.7%) | 411 (59.5%) | 228 (60.0%) | 916 (61.1%) |
Female | 151 (35.3%) | 280 (40.5%) | 152 (40.0%) | 583 (38.9%) |
Age, yrs |  |  |  |  | 0.614
Mean (SD) | 59.673 (11.365) | 60.301 (11.632) | 59.763 (11.499) | 59.985 (11.519) |
Range | 27.000 - 88.000 | 19.000 - 88.000 | 26.000 - 85.000 | 19.000 - 88.000 |

    summary(modelsum(bmi ~ age, adjust = ~sex, data = mockstudy),
            labelTranslations = list(sexFemale = "Female", age = "Age, yrs"))

| estimate | std.error | p.value | adj.r.squared | Nmiss
--- | --- | --- | --- | --- | ---
(Intercept) | 26.793 | 0.766 | < 0.001 | 0.004 | 33
Age, yrs | 0.012 | 0.012 | 0.348 |  |
Female | -0.718 | 0.291 | 0.014 |  |

## Modify labels after the fact

Another option is to add labels after you have created the object. To do this, you can use the form `labels(x) <- value` or use the pipe-able version, `set_labels()`.

    # the non-pipe version; somewhat clunky
    tmp <- freqlist(tab.ex)
    labels(tmp) <- c(arm = "Treatment Arm", sex = "Gender", mdquality.s = "LASA QOL")
    summary(tmp)

Treatment Arm | Gender | LASA QOL | Freq | Cumulative Freq | Percent | Cumulative Percent
--- | --- | --- | --- | --- | --- | ---
A: IFL | Male | 0 | 29 | 29 | 1.93 | 1.93
|  | 1 | 214 | 243 | 14.28 | 16.21
|  | NA | 34 | 277 | 2.27 | 18.48
| Female | 0 | 12 | 289 | 0.80 | 19.28
|  | 1 | 118 | 407 | 7.87 | 27.15
|  | NA | 21 | 428 | 1.40 | 28.55
F: FOLFOX | Male | 0 | 31 | 459 | 2.07 | 30.62
|  | 1 | 285 | 744 | 19.01 | 49.63
|  | NA | 95 | 839 | 6.34 | 55.97
| Female | 0 | 21 | 860 | 1.40 | 57.37
|  | 1 | 198 | 1058 | 13.21 | 70.58
|  | NA | 61 | 1119 | 4.07 | 74.65
G: IROX | Male | 0 | 17 | 1136 | 1.13 | 75.78
|  | 1 | 187 | 1323 | 12.47 | 88.26
|  | NA | 24 | 1347 | 1.60 | 89.86
| Female | 0 | 14 | 1361 | 0.93 | 90.79
|  | 1 | 121 | 1482 | 8.07 | 98.87
|  | NA | 17 | 1499 | 1.13 | 100.00

    # piped--much cleaner
    mockstudy %>%
      tableby(arm ~ sex + age, data = .) %>%
      set_labels(c(sex = "SEX", age = "Age, yrs")) %>%
      summary()

| A: IFL (N=428) | F: FOLFOX (N=691) | G: IROX (N=380) | Total (N=1499) | p value
--- | --- | --- | --- | --- | ---
SEX |  |  |  |  | 0.190
Male | 277 (64.7%) | 411 (59.5%) | 228 (60.0%) | 916 (61.1%) |
Female | 151 (35.3%) | 280 (40.5%) | 152 (40.0%) | 583 (38.9%) |
Age, yrs |  |  |  |  | 0.614
Mean (SD) | 59.673 (11.365) | 60.301 (11.632) | 59.763 (11.499) | 59.985 (11.519) |
Range | 27.000 - 88.000 | 19.000 - 88.000 | 26.000 - 85.000 | 19.000 - 88.000 |

    mockstudy %>%
      modelsum(bmi ~ age, adjust = ~ sex, data = .) %>%
      set_labels(list(sexFemale = "Female", age = "Age, yrs")) %>%
      summary()

| estimate | std.error | p.value | adj.r.squared | Nmiss
--- | --- | --- | --- | --- | ---
(Intercept) | 26.793 | 0.766 | < 0.001 | 0.004 | 33
Age, yrs | 0.012 | 0.012 | 0.348 |  |
Female | -0.718 | 0.291 | 0.014 |  |

## Add labels to a `data.frame`

`tableby()` and `modelsum()` also allow you to have label attributes on the data. Note that by default these attributes usually get dropped upon subsetting, but `tableby()` and `modelsum()` use the `keep.labels()` function to retain them.

    mockstudy.lab <- keep.labels(mockstudy)
    class(mockstudy$age)

[1] “integer”

    class(mockstudy.lab$age)

[1] “keep_labels” “integer”

To undo this, simply `loosen.labels()`:

    class(loosen.labels(mockstudy.lab)$age)

[1] “integer”

You can set attributes one at a time in two ways:

    attr(mockstudy.lab$sex, "label") <- "Sex"
    labels(mockstudy.lab$age) <- "Age, yrs"

…or all at once:

    labels(mockstudy.lab) <- list(sex = "Sex", age = "Age, yrs")
    summary(tableby(arm ~ sex + age, data = mockstudy.lab))

| A: IFL (N=428) | F: FOLFOX (N=691) | G: IROX (N=380) | Total (N=1499) | p value
--- | --- | --- | --- | --- | ---
Sex |  |  |  |  | 0.190
Male | 277 (64.7%) | 411 (59.5%) | 228 (60.0%) | 916 (61.1%) |
Female | 151 (35.3%) | 280 (40.5%) | 152 (40.0%) | 583 (38.9%) |
Age, yrs |  |  |  |  | 0.614
Mean (SD) | 59.673 (11.365) | 60.301 (11.632) | 59.763 (11.499) | 59.985 (11.519) |
Range | 27.000 - 88.000 | 19.000 - 88.000 | 26.000 - 85.000 | 19.000 - 88.000 |

You can pipe this, too.

    mockstudy %>%
      set_labels(list(sex = "SEX", age = "Age, yrs")) %>%
      modelsum(bmi ~ age, adjust = ~ sex, data = .) %>%
      summary()

| estimate | std.error | p.value | adj.r.squared | Nmiss
--- | --- | --- | --- | --- | ---
(Intercept) | 26.793 | 0.766 | < 0.001 | 0.004 | 33
Age, yrs | 0.012 | 0.012 | 0.348 |  |
SEX Female | -0.718 | 0.291 | 0.014 |  |

To extract labels from a `data.frame`, simply use the `labels()` function:

    labels(mockstudy.lab)

    ## $case
    ## NULL
    ##
    ## $age
    ## [1] "Age, yrs"
    ##
    ## $arm
    ## [1] "Treatment Arm"
    ##
    ## $sex
    ## [1] "Sex"
    ##
    ## $race
    ## [1] "Race"
    ##
    ## $fu.time
    ## NULL
    ##
    ## $fu.stat
    ## NULL
    ##
    ## $ps
    ## NULL
    ##
    ## $hgb
    ## NULL
    ##
    ## $bmi
    ## [1] "Body Mass Index (kg/m^2)"
    ##
    ## $alk.phos
    ## NULL
    ##
    ## $ast
    ## NULL
    ##
    ## $mdquality.s
    ## NULL
    ##
    ## $age.ord
    ## NULL

## When labels get long

`tableby()` and `modelsum()` both support the wrapping of long labels. Consider the `width=` argument in the `print()` function:

    mockstudy %>%
      set_labels(list(age = "This is a really long label for the arm variable")) %>%
      tableby(sex ~ age, data = .) %>%
      summary() %>%
      print(width = 20)

| Male (N=916) | Female (N=583) | Total (N=1499) | p value
--- | --- | --- | --- | ---
This is a really |  |  |  | 0.048
long label for the |  |  |  |
arm variable |  |  |  |
Mean (SD) | 60.455 (11.369) | 59.247 (11.722) | 59.985 (11.519) |
Range | 19.000 - 88.000 | 22.000 - 88.000 | 19.000 - 88.000 |