if_else 与 haven_labelled 列因错误 class 而失败
if_else with haven_labelled column fails because of wrong class
我有以下数据:
dat <- structure(list(value = structure(c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
label = "value: This is my label",
labels = c(`No` = 0, `Yes` = 1),
class = "haven_labelled"),
group = structure(c(1, 2, 1, 1, 2, 3, 3, 1, 3, 1, 3, 3, 1, 2, 3, 2, 1, 3, 3, 1),
label = "my group",
labels = c(first = 1, second = 2, third = 3),
class = "haven_labelled")),
row.names = c(NA, -20L),
class = c("tbl_df", "tbl", "data.frame"),
label = "test.sav")
如您所见,数据使用了来自 tidyverse 的 haven 包的特殊 class,即所谓的 labelled
列。
现在我想重新编码我的初始 value
变量,这样:
if group equals 1, value should stay the same, otherwise it should be missing
我正在尝试以下操作,但出现错误:
dat_new <- dat %>%
mutate(value = if_else(group != 1, NA, value))
# Error: `false` must be a logical vector, not a `haven_labelled` object
我了解到 dplyr 的 if_else 要求 if_else 命令中的真假检查相同 class 并且因为没有 NA 等价物对于 class 标记(例如类似于 NA_real_
的双打),代码可能会失败,对吧?
那么,如何重新编码我的初始变量并保留标签?
我知道我可以更改上面的代码并将 if_else
替换为 R 的基本版本 ifelse
。但是,这会删除所有标签并将值列强制转换为数字。
您可以使用以下难看的代码在 haven_labelled
class 中创建一个 NA 值:
haven::labelled(NA_real_, labels = attr(dat$value, "labels"))
我建议为此编写一个函数,例如
labelled_NA <- function(value)
haven::labelled(NA_real_, labels = attr(value, "labels"))
然后你的 mutate 代码就没那么丑了:
dat_new <- dat %>%
mutate(value = if_else(group != labelled_NA(value), value))
然后你得到
> dat_new[1:5,]
# A tibble: 5 x 2
value group
<dbl+lbl> <dbl+lbl>
1 NA 1 [first]
2 NA 2 [second]
3 0 [No] 1 [first]
4 0 [No] 1 [first]
5 NA 2 [second]
对于 group == 1
的情况,您可以尝试 dplyr::case_when
。如果没有匹配的案例,则返回 NA
:
dat %>% mutate(value = case_when(group == 1 ~ value))
我有以下数据:
dat <- structure(list(value = structure(c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
label = "value: This is my label",
labels = c(`No` = 0, `Yes` = 1),
class = "haven_labelled"),
group = structure(c(1, 2, 1, 1, 2, 3, 3, 1, 3, 1, 3, 3, 1, 2, 3, 2, 1, 3, 3, 1),
label = "my group",
labels = c(first = 1, second = 2, third = 3),
class = "haven_labelled")),
row.names = c(NA, -20L),
class = c("tbl_df", "tbl", "data.frame"),
label = "test.sav")
如您所见,数据使用了来自 tidyverse 的 haven 包的特殊 class,即所谓的 labelled
列。
现在我想重新编码我的初始 value
变量,这样:
if group equals 1, value should stay the same, otherwise it should be missing
我正在尝试以下操作,但出现错误:
dat_new <- dat %>%
mutate(value = if_else(group != 1, NA, value))
# Error: `false` must be a logical vector, not a `haven_labelled` object
我了解到 dplyr 的 if_else 要求 if_else 命令中的真假检查相同 class 并且因为没有 NA 等价物对于 class 标记(例如类似于 NA_real_
的双打),代码可能会失败,对吧?
那么,如何重新编码我的初始变量并保留标签?
我知道我可以更改上面的代码并将 if_else
替换为 R 的基本版本 ifelse
。但是,这会删除所有标签并将值列强制转换为数字。
您可以使用以下难看的代码在 haven_labelled
class 中创建一个 NA 值:
haven::labelled(NA_real_, labels = attr(dat$value, "labels"))
我建议为此编写一个函数,例如
labelled_NA <- function(value)
haven::labelled(NA_real_, labels = attr(value, "labels"))
然后你的 mutate 代码就没那么丑了:
dat_new <- dat %>%
mutate(value = if_else(group != labelled_NA(value), value))
然后你得到
> dat_new[1:5,]
# A tibble: 5 x 2
value group
<dbl+lbl> <dbl+lbl>
1 NA 1 [first]
2 NA 2 [second]
3 0 [No] 1 [first]
4 0 [No] 1 [first]
5 NA 2 [second]
对于 group == 1
的情况,您可以尝试 dplyr::case_when
。如果没有匹配的案例,则返回 NA
:
dat %>% mutate(value = case_when(group == 1 ~ value))