
Decode numeric category codes with an explicit code-to-label dictionary
Source:R/categorical_guard.R
deccodes.RdTurns a vector of category codes (for example 1, 2, 3
from an SPSS, Stata or SAS file) into the category labels they stand for,
using a code-to-label dictionary that you write out. Every code that occurs
in the data must be in the dictionary; a code without a label is an error
rather than a silent NA or a pass-through. Use it whenever a column
arrives as numbers that are really categories, before any table or model,
so that a group can never be renumbered by treating codes (or
as.numeric() on a factor of them) as the categories.
Arguments
- x
Vector of codes: numeric, integer, character or factor. A factor is read through its labels, not its integer codes; an ordered factor is treated the same as an unordered one (its level order is not used).
- vlabs
Named character vector, code = label, for example
c("1" = "White", "2" = "Black"). The names are the codes as they print withas.character(); the values are the labels. Codes in the dictionary that do not occur inxare allowed.- keepna
Logical, default
TRUE:NAcodes stayNAin the result.FALSEmakes anyNAcode an error, for columns where missingness should not occur.
Value
A character vector of labels, the same length as x, with
NA where x is NA. It carries a recode_audit
attribute: a list with mapping (the dictionary), kept
(character(0)) and checksum (64-character hexadecimal
SHA-256 of the code=label pairs).
Details
x is converted to character (a factor by its labels, a number by
as.character(), so 1 and 1.0 both become "1")
and every distinct non-missing code is looked up by name in
vlabs. The lookup itself is done by
grdrcd, so the result carries the same
recode_audit attribute, including a SHA-256 of the dictionary.
Errors:
vlabsnot a character vector with non-empty names;a code in
xthat is not a name ofvlabs(the message lists the unmapped codes);any
NAinxwhenkeepna = FALSE.
For a haven-style labelled vector, which carries its dictionary as a
labels attribute, use declbld, which returns a
factor with the levels in code order.
Examples
# codes from a survey file with their code book
race <- c(1, 2, 2, 3, NA)
book <- c("1" = "White", "2" = "Black", "3" = "Indigenous")
deccodes(race, book)
#> [1] "White" "Black" "Black" "Indigenous" NA
#> attr(,"recode_audit")
#> attr(,"recode_audit")$mapping
#> 1 2 3
#> "White" "Black" "Indigenous"
#>
#> attr(,"recode_audit")$kept
#> character(0)
#>
#> attr(,"recode_audit")$checksum
#> [1] "be0b0dcd1bb12223f6d28bc031e1accfd45a3f700d18c920b54d7d766905bdd0"
#>
# the dictionary that was applied is kept on the result
attr(deccodes(race, book), "recode_audit")$checksum
#> [1] "be0b0dcd1bb12223f6d28bc031e1accfd45a3f700d18c920b54d7d766905bdd0"
# a code with no label is refused, never passed through
try(deccodes(c(1, 2, 9), book))
#> Error : grdrcd: values with NO mapping: ‘9’. Every observed category must be mapped by name (or listed in `keep`); silent pass-through is how group labels get corrupted.
# missing codes can be refused too
try(deccodes(race, book, keepna = FALSE))
#> Error : deccodes: `x` has missing codes and keep_na = FALSE