jrecode() recodes a variable using a simple map string that specifies
how old values should be converted to new values. It is designed for
situations where you need to collapse categories, change numeric codes,
or recode dichotomies. Variable and value labels are handled automatically.
Map and labels rules can also produce missing values: plain system NA
via the NA / System / SYSMIS aliases, or
tagged missing values (.a through .z, or .A
through .Z) when the active convention is Stata or SAS. See
Missing values in the map
below for the canonical patterns under each convention.
Arguments
- data
A data frame containing the original variable.
- orig.var
The variable to recode (unquoted, e.g.
AgeGroup; a quoted name is accepted).- map
A quoted string specifying the recode rules, using the format
"old=new"with rules separated by semicolons. Multiple old values mapping to the same new value are separated by commas on the left side.An optional
elseclause controls what happens to values not covered by the map:No else clause: the function stops with a message if any values are left unmapped, so you can fix the map before proceeding.
else=NA(alsoelse=Systemorelse=SYSMIS): unmapped values are deliberately set to system NA.else=copy: unmapped values are carried across unchanged.else=.a(or any other marker,.athrough.z; Stata or SAS convention only): unmapped values are set to that Stata-style or SAS-style missing value.
Individual values can also be mapped to system NA using the same aliases:
"-5=NA","-5=System", or"-5=SYSMIS".The same aliases may also appear as an OLD value, converting plain
NAcells to a code:"NA=-98; else=copy"recodes everyNAto-98(declare the code afterward withjdeclare_missing()).NAmay be combined with numeric old values in one rule ("NA,-99=-98") and may be named in at most one rule. Only plainNAcells are affected; tagged missing values are never converted by anNArule. Under Stata or SAS convention the target may itself be a marker:"NA=.a".Under Stata or SAS convention, values can be mapped to Stata-style or SAS-style missing values by their markers:
"-99=.a; -98=.b".A lettered marker can also be an OLD value, recoding the cells that carry it (either case:
.aalso names a SAS-style.A):".a=-99"gives them a number,".a=NA"makes them plainNA, and".e=.c"re-letters them, merging them into.cif the variable already has it (a marker on the right needs Stata or SAS convention, as always). Markers and numbers may share a rule ("9,.a=-99"). A marker the map does not name is kept, with its label, whatever theelsesetting.The right-hand side may also be the word
missing(case-insensitive): the value is converted to your working convention's own missing form – a tagged marker under the Stata or SAS convention, or the first code from themissing.convention.codessetting injoptionsunder the SPSS convention, declared on the result automatically. The same map string therefore works under every setting:"8=missing; else=copy". The NA rule composes with it ("NA=missing"converts plainNAcells the same way), andlabels = "missing=Refused"labels whatever the keyword produced. If the column already carries the other convention's markers while yourmissing.conventionsetting is set, the call stops and shows both resolutions rather than guessing.Under the SPSS convention the code the keyword uses must be free: if the column already declares it, discretely or inside a declared range, the existing declaration is reused rather than added to; if it is an ordinary value in the column that the map leaves in place, or a value the map itself assigns, the call stops rather than sweep those cases into missingness; and if the declared codes the result keeps already fill what SPSS allows (three codes, or a range plus one code), the call stops and offers a declared code instead. Under the Stata or SAS convention the keyword always uses the first marker (
.a, or.A), so a map that also assigns that marker itself stops rather than merge two missing categories onto one marker; the message offers the next free marker, or the same marker for both when that is what you mean. When the variable already carries that marker – data from Stata often has its own.a– the recoded cases join it, and a note says so and gives the line that keeps them apart (the next free marker). Under every convention, alabels = "missing=..."that differs from the label the marker or code already has stops, since it would rename the cases already there: the message gives the line that keeps the two apart and the line that merges them on purpose, keeping the existing label.Examples:
"1=1; 2=0""1=1; 2,3=2; 4,5=3; else=NA""1=1; 2=0; else=copy""-5=System; else=copy""NA=-98; else=copy""3=1; 4=2; else=.a"(Stata or SAS convention only)".a=-99; .b=-98; else=copy"(a Stata-style variable to numeric codes, declared on the result)"8=missing; else=copy"(any convention)
- labels
Optional. A quoted string specifying value labels for the new variable, using the format
"code=Label Text"with rules separated by semicolons. If supplied, these labels are used for the codes they name; the labels of declared missing values the result keeps (see Details) ride alongside them unless the string labels the same code. A label may be written in quotes, with either mark, right after its equals sign, and a semicolon inside the quotes is then part of the label:"1=Yes; 9=\"Refused; not asked\"". An unquoted label reads as it is written.The left side of each rule may be a numeric code or, under Stata or SAS convention, a missing-value marker (
.athrough.z, or.Athrough.Z). A marker's label is stored on the marker itself, not on a numeric code. It may also be the wordmissing, labelling whatever the map'smissingtarget produced:labels = "missing=Refused".If omitted, the function attempts to transfer value labels automatically from the original variable. This works when the original variable has value labels and the mapping is one-to-one (no categories are collapsed). When categories are collapsed, labels cannot be transferred automatically and a note is printed.
Example:
"1=Male; 0=Female"or".a=Refused; .b=Don't know".- convention
Optional. One of
"spss","stata","sas", orNULL(default); any capitalization is accepted. Controls whether missing-value markers (.athrough.zor.Athrough.Z) are accepted in the map and labels arguments. Marker letters are matched case-insensitively; the stored markers take the convention's letter case (lowercase Stata-style under"stata", uppercase SAS-style under"sas"). Also decides what themissingkeyword produces. Inert when neither a marker normissingappears in either argument.- ...
Not used. An input
jrecode()does not take – a misspelled argument – stops with "unused input" and the name as typed, in place of R's own "unused argument".When
NULL, the convention is resolved from themissing.conventionsetting injoptions; if that is also unset, the call stops with a guided error asking you to choose – the package never infers a convention. Most users set the convention once at the top of a session viajoptions()(or in their.Rprofile) rather than supplying this argument on every call. See?joptionsfor details.
Value
A haven_labelled vector with the recoded values, variable
label, and (if supplied or auto-transferred) value labels applied. The
function returns the values rather than changing data: assign
the result to a column to keep it. Two assignment forms do that job:
Preserving (recommended):
MyData$AgeGroupR <- jrecode(MyData, AgeGroup, map = "...")adds a new column and keeps the original, so the two can be compared withjfreq()before the original is retired.Overwrite:
MyData$AgeGroup <- jrecode(MyData, AgeGroup, map = "...")replaces the variable in place. Nothing is wrong with this once the recode is verified, but the original values are gone.
SPSS users will recognize the pair: RECODE ... INTO new. is
the preserving form and bare RECODE the overwrite.
Details
The function accepts haven-labelled, plain numeric, and logical variables. Factor, character, and date/time variables are refused with a message naming the fix — recoding works with a variable's numeric values, so convert these to numeric first.
The variable label from the original variable is carried across automatically with "(recoded)" appended. If the original variable has no variable label, the variable name is used instead.
Value labels are handled in three ways, in order of priority:
If
labelsis supplied, those labels are used as-is.If
labelsis omitted and the original variable has value labels, they are automatically transferred to the new codes — provided the mapping is one-to-one (no collapsing). For example, recoding 1/2 to 1/0 will carry "Yes" and "No" across to the new codes automatically.If categories are collapsed (multiple old values map to one new value), automatic transfer is not possible and a note is printed directing you to supply labels manually. Recoding onto a value that
else=copyalso carries across ("5=4; else=copy") collapses two categories the same way.
Labels move with lettered markers as they do with numbers: a marker
recoded to a number or to another marker takes its label along, and a
value recoded to a marker gives the marker its label. Where a label
would land on a value that keeps a label of its own ("-99=-98",
or ".b=.a" on a variable with both markers), the value keeps
its own; several different labels landing on one new value are all
dropped. Labels that move onto a declared missing value or a marker
also ride beside a supplied labels string, as the labels of
kept declared values do.
NA values in the original variable are carried across as NA unless the
map names NA as an old value (for example "NA=-98"); the
else setting never converts NA. An NA rule affects plain
NA cells only — tagged missing values (Stata-style or
SAS-style) are declared missings and are preserved with their tags
unless the map names them as old values (".a=-99"). Declared
SPSS-style missing values on the
original variable are likewise preserved, whether declared as discrete
codes or as a range: a declared code the map does not name, and every
value inside a declared range, are carried onto the result with the
declaration and their labels under every else setting, and a
note names the values the data hold (map them to NA explicitly
to convert them instead). A declared code the map names is recoded like
any other value; a range always carries whole, so a value the map
recodes into the range is missing on the result.
A declared missing value the map moves onto a new code stays missing
when the new code looks like a coded missing value (the check
jload describes under Coded missing values):
"-99=-88; else=copy" on a variable declaring -99 declares
-88 on the result, with the label of -99 and a note
saying so, and -99 is no longer declared. A lettered marker
recoded to a number works the same way (".a=-99"). A new code
that does not pass the check becomes an ordinary value – deliberately
so for "-99=6", which makes refusals a category, but also for a
negative code on a variable with large values, such as incomes, where
the check finds nothing unusual; declare such a code with
jdeclare_missing(). So does a new code that also receives
ordinary values. A result that would hold both such a declared code and
a lettered marker, or more declared codes than SPSS allows, stops the
call with a message.
A variable holds one convention. When the original variable's
SPSS-style declaration survives the map (a range always does; a discrete
code does unless the map names it), Stata-style or SAS-style markers in
the map or labels are refused with a pointer to jconvert(). A map
that names every declared code ("-99=.a; -98=.b; else=copy"
under Stata convention) leaves nothing SPSS-style behind and is the
one-column migration pattern.
Values that merely look like coded missing values (e.g. -99, -9, 999)
but are not declared are never changed on their own. Left unmapped
with no else clause, they are named in the error that stops the
call, with a nudge toward jdeclare_missing(); carried across by
else=copy, they draw an advisory note at the full
joutput tier. Recoding values to a code that looks
like a missing value draws a note suggesting the declaration.
If the map does not include an else clause and there are unmapped
values in the variable, the function stops with a message listing the
unmapped values so you can fix the map before proceeding.
If the map specifies values that do not exist in the original variable,
nothing is recoded for them and an advisory note says so at the full
joutput tier. This helps catch typos in the map string.
Missing values in the map. The package supports three
conventions for representing declared missing values, and the syntax
for producing them from jrecode() depends on which one is
active. A convention becomes active via
joptions(missing.convention = ...) or this call's
convention argument; with neither set, a call that produces
declared missing values stops with a guided error asking you to choose.
Under SPSS convention, declared missing values are real numeric codes carrying metadata that flags them as missing. The two-step canonical pattern is:
df$EducR <- jrecode(df, Education,
map = "1,2=1; 3=2; 4,5=3; -99,-98=-99",
labels = "1=High school or less; 2=Some college; 3=Degree")
jdeclare_missing(df, EducR, codes = c(Refused = -99), modify = TRUE)The jrecode() call assigns the numeric code -99; the
subsequent jdeclare_missing() call attaches the label and flags
-99 as missing. Labeling -99 inside the labels
argument is unnecessary — jdeclare_missing() owns that label.
The same two-step pattern serves data whose missingness arrived as
plain NA (data born in R, or read from a CSV): map =
"NA=-98; else=copy" converts the NA cells to the numeric code, and
jdeclare_missing() declares it.
Missingness that arrived as Stata-style or SAS-style markers takes one
step: naming the markers moves them to codes that are declared on the
result (map = ".a=-99; .b=-98; else=copy"), as described
above. jconvert(to = "spss") does the same for every such
variable in a data frame, taking the codes from your setting.
Under Stata convention, declared missing values are typed
missing cells marked with Stata-style tags (.a through
.z). The single-call canonical pattern names the same codes:
df$EducR <- jrecode(df, Education,
map = "1,2=1; 3=2; 4,5=3; -99,-98=.a",
labels = "1=High school or less; 2=Some college; 3=Degree; .a=Refused")Under Stata convention, jdeclare_missing() is not needed for this
pattern — jrecode() handles both the value recoding and the
Stata-style missing-value labeling in one call. Naming the declared
codes is what makes the call legal on a column that carries SPSS-style
missing values: a map that left -99 and -98 in place
(else=.a alone) would put a marker beside them and is refused.
SAS convention works the same way with SAS-style missing
values (.A through .Z). Markers in the map and labels are
matched case-insensitively, and the stored markers take the active
convention's letter case: lowercase under Stata convention, uppercase
under SAS convention.
Writing these markers while the active convention is SPSS raises an
error naming the mismatch and the two ways out:
restate the markers as numeric codes to stay in SPSS convention, or
switch convention with joptions(missing.convention = ...) (or
with this call's convention argument). The error does not
rewrite the call for you: the SPSS-style codes would have to be taken
from the missing.convention.codes setting in joptions,
which cannot be known to be free of collision with values already in the
column. The two-call SPSS-style pattern is documented above.
See also
jdeclare_missing for declaring missing values on a
column after a recode (the SPSS-style canonical pattern).
jrelabel for applying labels to an existing variable
after a recode.
joptions for the session-level
missing.convention setting.
jstats for the package overview,
workflow conventions, and complete function listing.
Examples
# Recode with explicit labels (a 1/2 dichotomy to 0/1)
df <- community
df$OwnsHome01 <- jrecode(df, OwnsHome,
map = "1=1; 2=0",
labels = "0=No; 1=Yes")
#> Note: This call changes df only if you assign the result:
#> df$<name> <- jrecode(...)
#> To check the recode landed correctly, compare jfreq() on the original and the
#> new column.
# The data frame may also be given by name
df$OwnsHome01 <- jrecode(data = df, OwnsHome, map = "1=1; 2=0",
labels = "0=No; 1=Yes")
#> Note: This call changes df only if you assign the result:
#> df$<name> <- jrecode(...)
#> To check the recode landed correctly, compare jfreq() on the original and the
#> new column.
# Collapse categories (must supply labels)
df$RegionR <- jrecode(df, Region,
map = "1,2=1; 3,4=2",
labels = "1=North or South; 2=East or West")
#> Note: This call changes df only if you assign the result:
#> df$<name> <- jrecode(...)
#> To check the recode landed correctly, compare jfreq() on the original and the
#> new column.
# Use else=copy to carry unspecified values across unchanged
df$EducR <- jrecode(df, Education,
map = "5=4; else=copy",
labels = "4=Bachelor's degree or higher")
#> Note: -99 ["Refused"], -98 ["Don't know"] are declared missing values and were
#> kept on the recoded variable.
#> To convert them to plain NA instead, map them to NA (for example -99=NA).
#>
#> Note: This call changes df only if you assign the result:
#> df$<name> <- jrecode(...)
#> To check the recode landed correctly, compare jfreq() on the original and the
#> new column.
# Use else=NA to deliberately drop unspecified values to system NA
df$EducR2 <- jrecode(df, Education,
map = "4=1; 5=1; else=NA",
labels = "1=College degree")
#> Note: -99 ["Refused"], -98 ["Don't know"] are declared missing values and were
#> kept on the recoded variable.
#> To convert them to plain NA instead, map them to NA (for example -99=NA).
#>
#> Note: This call changes df only if you assign the result:
#> df$<name> <- jrecode(...)
#> To check the recode landed correctly, compare jfreq() on the original and the
#> new column.
# Convert a specific coded missing value to system NA
df$EducR3 <- jrecode(df, Education, map = "-99=System; else=copy")
#> Note: -98 ["Don't know"] is a declared missing value and was kept on the
#> recoded variable.
#> To convert it to a plain NA instead, add -98=NA to the map.
#>
#> Note: This call changes df only if you assign the result:
#> df$<name> <- jrecode(...)
#> To check the recode landed correctly, compare jfreq() on the original and the
#> new column.
# Give plain NA cells a codable value, then declare it. Declaring on a
# plain column needs a chosen missing-value convention (the package
# never infers one), so choose it first:
joptions(missing.convention = "spss")
#> Options Settings
#> Missing-value convention: SPSS-style
#> SPSS-style missing value codes: -99, -98, -97
#> Run joptions() to see all settings.
#>
df$AgeR <- jrecode(df, Age, map = "NA=-98; else=copy")
#> Note: This call changes df only if you assign the result:
#> df$<name> <- jrecode(...)
#> To check the recode landed correctly, compare jfreq() on the original and the
#> new column.
df <- jdeclare_missing(df, AgeR, codes = c("Not recorded" = -98))
#> Declared SPSS-style missing values on AgeR:
#> -98 ["Not recorded"] (not present in the data)
#>
#> This call changes df only if you assign the result:
#> df <- jdeclare_missing(df, AgeR, ...)
#>
#> To change df directly, rerun with modify = TRUE:
#> jdeclare_missing(df, AgeR, ..., modify = TRUE)
# Stata convention: Stata-style missing values in map and labels, named
# by their markers (single call; convention = "stata" scopes the choice
# to this call only).
# Education carries SPSS-style missing values (-99, -98); naming them in
# the map moves them to the marker in the same call.
df$EducR4 <- jrecode(df, Education,
map = "1,2=1; 3,4,5=2; -99,-98=.a",
labels = "1=No college; 2=College; .a=Refused",
convention = "stata")
#> Note: This call changes df only if you assign the result:
#> df$<name> <- jrecode(...)
#> To check the recode landed correctly, compare jfreq() on the original and the
#> new column.
# SAS convention: the same single-call pattern; markers are matched
# case-insensitively and store in uppercase (.A)
df$EducR5 <- jrecode(df, Education,
map = "1,2=1; 3,4,5=2; -99,-98=.a",
labels = "1=No college; 2=College; .a=Refused",
convention = "sas")
#> Note: This call changes df only if you assign the result:
#> df$<name> <- jrecode(...)
#> To check the recode landed correctly, compare jfreq() on the original and the
#> new column.
# Using juse() default
juse(df)
#> Default data frame set to: df
df$RegionR2 <- jrecode(Region, map = "1,2=1; 3,4=2",
labels = "1=North or South; 2=East or West")
#> Note: This call changes df only if you assign the result:
#> df$<name> <- jrecode(...)
#> To check the recode landed correctly, compare jfreq() on the original and the
#> new column.