jdeclare_missing() declares missing values on one or more
variables. Declared missing values are specific data values –
typically negative codes such as -99, Stata-style tagged
markers such as .a, or on a text variable words such as
"UNKNOWN" – that indicate why a value is
missing (refused, don't know, not applicable, etc.) rather than
simply that it is missing. Once declared, those cells are
automatically excluded from analyses but remain visible in the data
for diagnostic purposes (see jfreq()). The haven package and
its documentation call these user-defined missing values.
The function operates in declarative mode: what a call mentions, it
replaces; what it omits survives. Supplying codes replaces the
column's discrete-code set; supplying range replaces the
column's missing-value range; an existing range survives a codes-only
call, and existing discrete codes survive a range-only call. A second
call therefore replaces, not augments, whichever parts it names –
matching SPSS's MISSING VALUES and Stata's mvdecode
semantics, neither of which has an additive form. When prior
declarations are dropped, a note lists them so the destructive aspect
of the replacement is not silent.
Variables are given either as unquoted names (jdeclare_missing(df,
MathScore, EnglishScore, codes = c(-99))) or as a character vector
via vars = (the programmatic form, e.g.
vars = offence_cols). A multi-variable call applies the same
declaration to every named column, all-or-nothing: if any column
fails a check, no column is changed. There is deliberately no
whole-data-frame default – declaring a code frame-wide would flag it
missing even on columns where that value is legitimate data. To
declare on every column, pass vars = names(data) explicitly.
Usage
jdeclare_missing(
data,
...,
codes = NULL,
labels = NULL,
range = NULL,
vars = NULL,
convention = NULL,
missing.notice = TRUE,
modify = FALSE
)Arguments
- data
A data frame containing the variable(s).
- ...
The variable(s) to declare missing values on, as unquoted names (e.g.
Income, orMathScore, EnglishScore). Use either...orvars, not both. All arguments after the variables must be named.- codes
The values to declare as missing: numbers, or on a text variable the values themselves in quotes, such as
codes = "UNKNOWN"(see the Text variables section). Accepts two forms:- Option A (separate codes and labels)
Unnamed numeric vector; labels supplied via the
labelsargument. E.g.codes = c(-99, -98), labels = "-99=Refused; -98=Don't know".- Option C (haven-style named vector)
Named numeric vector; names are the labels. E.g.
codes = c(Refused = -99, `Don't know` = -98).
On a column that already carries Stata-style or SAS-style missing values, codes may name the markers directly, as quoted strings, e.g.
codes = c(Refused = ".a")– the string".a"names the.amarker (or.Aon a SAS-style column: the letter case you type is accepted either way and canonicalized to the column's convention). A quoted marker is refused on a column with no tagged missing values to label (see the Missing-Values Convention section).A quoted marker may name one that no case currently carries – useful for FORWARD-DECLARING a label before recoding values into it. The label attaches, nothing in the data changes, and the notification says the marker is not present in the data. Such a label survives a save to Stata format (.dta) and the load back, and
jconvert(to = "spss")declares its code like any other marker's.A quoted marker given with no label is a no-op on an already-tagged column: the cells are already missing, so the only act available is naming a marker, and the call reports that it changed nothing. This differs from the numeric form, where a bare code IS the declaration.
- labels
Optional. A quoted string in the form
"value=label; value=label"pairing labels with codes (Option A only). Must beNULLwhencodesis named (Option C). It may also stand alone, with nocodes: the values named in the string are then the codes declared, solabels = "-99=Refused; -98=Don't know"declares and labels both codes in one argument (andlabels = ".a=Refused"names a marker on a tagged column). 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. When arangeis in effect (supplied in this call, or already on the column), entries may also name values inside the range: those attach as value labels on the in-range values without becoming discrete declared codes (see the Missing-value ranges section). On a text variable the values are text, as inlabels = "REF=Refused; UNKNOWN=Unknown": a value holding an equals sign or a semicolon goes in quotes, andblanknames the blank cells, as in the maps ofjencode.- range
Optional. A length-2 numeric vector declaring a missing-value RANGE (band), e.g.
range = c(-99, -51)– every value from the first bound through the second is treated as missing. The SPSS parallel isMISSING VALUES X (-99 THRU -51). Bounds may be non-integer, and one bound may be infinite (c(-Inf, -51)is SPSS'sLO THRU -51). A missing-value range can exist only under SPSS convention: combiningrangewith the Stata or SAS convention – as a per-call argument or as thejoptions()setting – or with quoted markers is refused, and the refusal teaches the two-step route (declare the range under SPSS convention, thenjconvert()the column) when the range covers few enough values to convert. When no convention is selected anywhere, a range declaration stops and asks forconvention = "spss"on the call. SPSS allows at most ONE discrete code alongside a range, and the check applies to the column's composed result (what this call supplies plus what already survives on the column), so a declaration that a.savfile could not hold is refused here rather than at save time. A text variable takes no range.- vars
Optional. A character vector of variable names, the programmatic alternative to unquoted names in
...(e.g.vars = c("Age", "Income"), orvars = offence_colswhereoffence_colsholds the names). Use eithervarsor..., not both.- convention
Optional. One of
"spss","stata", or"sas"(any capitalization is accepted); sets the convention for this call on columns that carry no missing-value declaration yet. A column that already carries the other convention's missing values is not overridden: the call stops and offers the two remedies (drop the argument to follow the column's form, orjconvert()the column first). WhenNULL(the default), the convention is resolved from the column's existing missing-value declaration (if any), then from themissing.conventionsetting injoptions; when neither supplies one, the call stops with a guided error asking you to choose – the package never infers a convention for a fresh declaration. Arangerequires SPSS convention (seerange). The SAS convention behaves as the Stata convention with uppercase markers: markers are stored and labeled as.A-.Z. A quoted marker's letter case is accepted either way under both tagged conventions; the case written to the column follows the resolved convention. A text variable's missing values are SPSS-style whatever the setting, so"stata"and"sas"are refused for one.- missing.notice
Logical. When
TRUE(the default), the function prints a notification summarizing what was declared, plus a reminder of how to keep the result. Under SPSS convention the notification lists the variable's resulting declaration, not only what the call named: a range or code the variable keeps from an earlier call is marked "already declared", a code with no value label is marked "no label", and a code or range that no case holds is marked "not present in the data" (the mark a mistyped code gets, such as -77 for -99). In a call on several variables that last mark is given only when none of the listed variables holds the value. SetFALSEto suppress.- modify
Logical. When
TRUE, the declaration is written back onto the data frame named in the call (or onto thejuse()default when the data argument is omitted), so no assignment is needed – the recommended workflow, since a declaration lost to a forgotten assignment silently poisons later statistics. Requires the data frame to be given as a plain name. WhenFALSE(the default), the caller's data frame is untouched; assign the returned data frame to keep the declaration.
Value
The data frame, with the specified variable(s) updated to
carry the declared missing values, returned invisibly. With the
default modify = FALSE, the caller's data frame is unchanged
until the result is assigned back. With modify = TRUE, the
change is also written back onto the caller's data frame, and the
returned copy can be ignored.
Missing-Values Convention
Under SPSS convention, codes are declared as numeric values via the
column's na_values attribute (haven's representation of
SPSS-style missing values). The data cells themselves are unchanged;
only the metadata that flags certain values as missing is added.
Under Stata or SAS convention with tagged missing-value input (quoted
markers such as ".a"), the function attaches value labels to
the column's existing tagged missing-value markers. This
requires the column to already carry tagged missing values –
either tagged cells, or markers previously declared through value
labels (a marker may be labeled before any cases carry it, so a
declaration made early in data collection is complete for later
data). The letter case you type is accepted either way and canonicalized
to the resolved convention: lowercase markers under Stata convention,
uppercase under SAS. Quoted markers against a column with no tagged
missing values are refused identically under every convention source: on a
plain column the error points at jrecode() (which creates
tagged cells from numeric codes); on a column carrying SPSS-style
declarations it points at jconvert().
Note that on a plain numeric column with plain numeric codes and no
convention argument, the resolved convention decides the
outcome: under SPSS convention the numbers stay in the cells and are
flagged missing; under Stata or SAS convention the matching cells
are converted to markers and the numbers leave the data. This is the
one place joptions(missing.convention = ...) changes what
happens to data (see the examples).
Under Stata or SAS convention with numeric input, the function
converts matching cells to tagged missing-value markers (SAS
convention writes the same letters uppercase). The
mapping is ordering-based: codes sorted by absolute value
descending, more-negative-first as tie-breaker, then assigned
.a, .b, .c, .d in that order (.A,
.B, ... under SAS convention). The
assignment proceeds independently of the missing.convention.codes
setting in joptions (which only governs the reverse
Stata-to-SPSS direction).
The letters are taken from the start of the alphabet whatever the
variable already holds, so a code is refused when its letter is one
the variable already carries, in its cells or as a labeled value:
converting -99 to .a on a variable whose .a
cells mean "Skipped" would put two kinds of missing data on one
marker. The message gives two jrecode() calls that run: one
recodes the codes to markers the variable does not use, which keeps
the kinds distinct; the other recodes them to the markers they would
have taken, for kinds that mean the same thing.
Missing-value ranges
A range declares a whole band of values missing at once – the form
commercial statistical software uses when a study's missing-value codes
share a band (e.g. every code from -99 through -51). SPSS accepts at
most three discrete missing values, OR a range, OR a range plus one
discrete value; jdeclare_missing() enforces the same rule on the
composed result of each call, so a declaration is refused at the
moment it becomes illegal rather than when jsave() later
refuses the file. A range-only call is complete in itself
(jdeclare_missing(df, X, range = c(-99, -51))).
Values inside the band may carry value labels: with a range in
effect, labels entries that match no discrete code but fall
inside the band attach as ordinary value labels on those values.
They do not become discrete declared codes – the band already
covers them – but analysis output that breaks out in-range values
can then show their meanings. Because a range replaces the column's
existing range and existing discrete codes survive a range-only
call, a column already carrying two or more discrete codes cannot
take a range in the same declaration; the call is refused with the
surviving codes named. When the new range no longer covers all of
the old one, a note names the range as it was and counts the cases
that are no longer missing.
Text variables
On a text variable the codes are the values themselves, in quotes:
jdeclare_missing(df, Marital, codes = "UNKNOWN"), or with labels,
codes = c(Refused = "REF") or labels = "REF=Refused". They
are declared SPSS-style – the form SPSS's MISSING VALUES gives a
string variable, and the only form a text value has – under every
missing.convention setting and with none selected, so no
convention needs choosing first. Under a Stata or SAS setting a note
says so; convention = "stata" or "sas" and a range
are refused for text. At most three values may be declared, the SPSS
limit on a string variable.
A value matches the cells that hold it exactly as stored: letter case
and outer spaces count, as in SPSS. After declaring, a note names any
values that differ from a declared one only in case or outer spaces
("Unknown" beside "UNKNOWN"), with their counts, and
gives the call that declares them too – naming the values already
declared, since a call replaces a variable's declaration – or, past
three values, points to jencode.
codes = "" declares every blank cell missing – empty, or holding
only spaces or tabs – as SPSS declares a blank string missing;
otherwise jstats counts blank cells as valid values and never assumes
they are missing.
Numbers given for a text variable are refused with the call to run, the
numbers in quotes. A call naming text and numeric variables together
declares numbers on the numeric ones or words on the text ones, and
refuses the others with the call to run. To keep the values in an SPSS
file, each must be 8 characters or fewer: jsave() refuses a
longer one, which the file would cut short.
Mixed conventions and file export
A single data frame may carry columns with SPSS-style and columns
with Stata-style missing values. In-memory analysis and display
tolerate the mix without issue (each column renders in its native
form). The constraint shows up at file-export time: .sav
cannot represent Stata-style missing values; .dta cannot
represent SPSS-style na_values declarations; .xpt can
represent neither
form. jsave() pre-flights the DF
against the destination format and errors with a pointer to
jconvert() when the mix is incompatible. The
post-declaration mismatch notice emitted at the bottom of this
function's output exists to alert you early if a declaration
ends up out of step with the rest of its DF.
Examples
# A fresh declaration needs a chosen missing-value convention; the
# package never infers one. Choose SPSS convention for these examples:
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.
#>
# clinic$MoodRating arrives "dirty": -99/-98 sit in the data as
# ordinary numbers (the state after a CSV or Excel import), so summary
# statistics are poisoned until the codes are declared missing.
df <- clinic
jdesc(df, MoodRating) # mean dragged far down by -99/-98
#> Descriptive Statistics
#>
#> 70 Cases in the 1 Variable Pool
#>
#> Variable Total Non_missing Min Max Mean SD
#> ---------- ----- ----------- --- --- ------ ------
#> MoodRating 70 70 -99 9 -4.943 31.477
#>
# SPSS form: declare -99 and -98 as missing, with labels. modify = TRUE
# writes the declaration back onto df in one step -- the recommended
# workflow.
jdeclare_missing(df, MoodRating,
codes = c(-99, -98),
labels = "-99=Refused; -98=Don't know",
modify = TRUE)
#> Declared SPSS-style missing values on MoodRating in df:
#> -99 ["Refused"]
#> -98 ["Don't know"]
#>
#> To keep it across sessions, save the data frame:
#> jsave(df, "df.rds")
jdesc(df, MoodRating) # codes now excluded as missing
#> Descriptive Statistics
#>
#> 70 Cases in the 1 Variable Pool
#>
#> Variable Total Non_missing Min Max Mean SD
#> ---------- ----- ----------- --- --- ----- -----
#> MoodRating 70 63 1 9 5.460 1.702
#>
# Equivalent without modify: assign the returned data frame back
df2 <- clinic
df2 <- jdeclare_missing(df2, MoodRating,
codes = c(-99, -98),
labels = "-99=Refused; -98=Don't know")
#> Declared SPSS-style missing values on MoodRating:
#> -99 ["Refused"]
#> -98 ["Don't know"]
#>
#> This call changes df2 only if you assign the result:
#> df2 <- jdeclare_missing(df2, MoodRating, ...)
#>
#> To change df2 directly, rerun with modify = TRUE:
#> jdeclare_missing(df2, MoodRating, ..., modify = TRUE)
# Equivalent using named codes (one step instead of codes + labels)
df3 <- jdeclare_missing(clinic, MoodRating,
codes = c("Refused" = -99, "Don't know" = -98))
#> Declared SPSS-style missing values on MoodRating:
#> -99 ["Refused"]
#> -98 ["Don't know"]
#>
#> This call changes clinic only if you assign the result:
#> clinic <- jdeclare_missing(clinic, MoodRating, ...)
#>
#> To change clinic directly, rerun with modify = TRUE:
#> jdeclare_missing(clinic, MoodRating, ..., modify = TRUE)
# The data frame may also be given by name, or set once with juse()
df3 <- jdeclare_missing(data = clinic, MoodRating, codes = c(-99, -98))
#> Declared SPSS-style missing values on MoodRating:
#> -99 (no label)
#> -98 (no label)
#>
#> This call changes clinic only if you assign the result:
#> clinic <- jdeclare_missing(clinic, MoodRating, ...)
#>
#> To change clinic directly, rerun with modify = TRUE:
#> jdeclare_missing(clinic, MoodRating, ..., modify = TRUE)
juse(clinic)
#> Default data frame set to: clinic
df3 <- jdeclare_missing(MoodRating, codes = c(-99, -98))
#> Declared SPSS-style missing values on MoodRating:
#> -99 (no label)
#> -98 (no label)
#>
#> This call changes clinic only if you assign the result:
#> clinic <- jdeclare_missing(clinic, MoodRating, ...)
#>
#> To change clinic directly, rerun with modify = TRUE:
#> jdeclare_missing(clinic, MoodRating, ..., modify = TRUE)
juse(NULL)
#> Default data frame cleared.
# A missing-value RANGE: every value from -99 through -51 is missing.
# SPSS parallel: MISSING VALUES MoodRating (-99 THRU -51).
df4 <- jdeclare_missing(clinic, MoodRating, range = c(-99, -51))
#> Declared SPSS-style missing values on MoodRating:
#> range -99 to -51
#>
#> This call changes clinic only if you assign the result:
#> clinic <- jdeclare_missing(clinic, MoodRating, ...)
#>
#> To change clinic directly, rerun with modify = TRUE:
#> jdeclare_missing(clinic, MoodRating, ..., modify = TRUE)
# Range plus labeled values inside the band, on several variables at
# once. The same declaration lands on every named column,
# all-or-nothing.
if (FALSE) { # \dontrun{
jdeclare_missing(mydata, vars = c("Theft", "Assault", "Burglary"),
range = c(-99, -51),
labels = "-99=Refused; -61=Not applicable",
modify = TRUE)
} # }
# Stata-style: label Stata-style missing-value cells. The jrecode() call
# turns the literal codes into tagged cells; jdeclare_missing() labels them
# by naming the markers as quoted strings.
df5 <- clinic
df5$Mood2 <- jrecode(df5, MoodRating,
map = "-99=.a; -98=.b; else=copy",
convention = "stata")
#> Note: This call changes df5 only if you assign the result:
#> df5$<name> <- jrecode(...)
#> To check the recode landed correctly, compare jfreq() on the original and the
#> new column.
jdeclare_missing(df5, Mood2,
codes = c("Refused" = ".a", "Don't know" = ".b"),
modify = TRUE)
#> Named Stata-style missing values on Mood2 in df5:
#> .a is now "Refused"
#> .b is now "Don't know"
#>
#> To keep it across sessions, save the data frame:
#> jsave(df5, "df5.rds")
#>
#> Note: Mood2 uses Stata-style missing values, but your missing.convention
#> setting is "spss".
#> To convert the data frame, run:
#> jconvert(df5, to = "spss", modify = TRUE)
#> To keep Stata-style instead, change the setting:
#> joptions(missing.convention = "stata")
#>
#> Note: Mood2 uses Stata-style missing values, but other columns in df5
#> are SPSS-style.
#> To align Mood2 with the rest, run:
#> jconvert(df5, vars = "Mood2", to = "spss", modify = TRUE)
# A text variable: the values themselves, in quotes, declared SPSS-style
# under every setting. codes = "" declares the blank cells.
df8 <- data.frame(Marital = c("Married", "UNKNOWN", "Single", "",
"UNKNOWN", "Married"))
df8 <- jdeclare_missing(df8, Marital, codes = c(Unknown = "UNKNOWN"))
#> Declared SPSS-style missing values on Marital:
#> UNKNOWN ["Unknown"]
#>
#> This call changes df8 only if you assign the result:
#> df8 <- jdeclare_missing(df8, Marital, ...)
#>
#> To change df8 directly, rerun with modify = TRUE:
#> jdeclare_missing(df8, Marital, ..., modify = TRUE)
df8 <- jdeclare_missing(df8, Marital, codes = c("UNKNOWN", ""))
#> Declared SPSS-style missing values on Marital:
#> <blank> (no label)
#> UNKNOWN ["Unknown"]
#>
#> This call changes df8 only if you assign the result:
#> df8 <- jdeclare_missing(df8, Marital, ...)
#>
#> To change df8 directly, rerun with modify = TRUE:
#> jdeclare_missing(df8, Marital, ..., modify = TRUE)
jfreq(df8, Marital)
#> Frequencies
#>
#> 6 Cases in the 1 Variable Pool
#>
#> Marital
#>
#> Freq Total % Valid % Cum. %
#> ------------------- ---- ------- ------- ------
#> Valid
#> Married 2 33.33 66.67 66.67
#> Single 1 16.67 33.33 100.00
#> Total valid 3 50.00 100.00
#>
#> Missing
#> <blank> (no label) 1 16.67 -- --
#> UNKNOWN ["Unknown"] 2 33.33 -- --
#> Total missing 3 50.00
#>
#> Total 6 100.00
#>
if (FALSE) { # \dontrun{
# The same neutral call -- plain numeric codes, no convention argument,
# plain column -- forks on joptions(missing.convention = ...):
joptions(missing.convention = "spss")
df6 <- jdeclare_missing(clinic, MoodRating, codes = c(-99))
# -99 stays in the cells, flagged as missing (SPSS-style declaration)
joptions(missing.convention = "stata")
df7 <- jdeclare_missing(clinic, MoodRating, codes = c(-99))
# -99 cells become the .a marker; the number -99 leaves the data
} # }