SAS: IF-THEN-ELSE, IFN / IFC, SELECT
Use if_else() for one condition and two results. Use case_when() for several branches.
Quick reference
library(dplyr)
df |>
mutate(
AGEGR1 = if_else(AGE < 65L, "<65", ">=65")
)
df |>
mutate(
AESEVN = case_when(
AESEV == "MILD" ~ 1L,
AESEV == "MODERATE" ~ 2L,
AESEV == "SEVERE" ~ 3L,
TRUE ~ NA_integer_
)
)
if_else(cond, true, false) |
IFN / IFC, or if then ... else |
case_when(cond ~ val, ...) |
SELECT / nested IF-THEN-ELSE |
case_when(..., TRUE ~ other) |
OTHERWISE / final else |
Trap: dplyr::if_else() is stricter on types than base ifelse(). Prefer if_else() in dplyr pipelines. case_when() stops at the first true condition.
Worked examples below.
Two-way: if_else()
Attaching package: 'dplyr'
The following objects are masked from 'package:stats':
filter, lag
The following objects are masked from 'package:base':
intersect, setdiff, setequal, union
dm <- data.frame(
USUBJID = c("STD-001-0001", "STD-001-0002", "STD-001-0003"),
AGE = c(54L, 70L, NA_integer_)
)
dm |>
mutate(AGEGR1 = if_else(AGE < 65L, "<65", ">=65"))
USUBJID AGE AGEGR1
1 STD-001-0001 54 <65
2 STD-001-0002 70 >=65
3 STD-001-0003 NA <NA>
When AGE is NA, if_else() returns NA for that row (unless you set missing=).
SAS ifc(age < 65, "<65", ">=65") is the same idea for character results.
Multi-way: case_when()
ae <- data.frame(
USUBJID = c("STD-001-0001", "STD-001-0002", "STD-001-0003", "STD-001-0004"),
AESEV = c("MILD", "MODERATE", "SEVERE", NA_character_)
)
ae |>
mutate(
AESEVN = case_when(
AESEV == "MILD" ~ 1L,
AESEV == "MODERATE" ~ 2L,
AESEV == "SEVERE" ~ 3L,
TRUE ~ NA_integer_
)
)
USUBJID AESEV AESEVN
1 STD-001-0001 MILD 1
2 STD-001-0002 MODERATE 2
3 STD-001-0003 SEVERE 3
4 STD-001-0004 <NA> NA
The first matching condition wins. End with TRUE ~ ... as the catch-all (SAS OTHERWISE).
if_else() checks that true and false values share a type. Base ifelse() is looser and often surprises with factors and dates.
For "first non-missing of several columns," use coalesce() (see Coalesce), not case_when().