0

I have the following data:

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")

As you can see, the data uses a special class from tidyverse's haven package, so called labelled columns.

Now I want to recode my initial value variable such that:

if group equals 1, value should stay the same, otherwise it should be missing

I was trying the following, but getting an error:

dat_new <- dat %>%
  mutate(value = if_else(group != 1, NA, value))
# Error: `false` must be a logical vector, not a `haven_labelled` object

I got so far as to understand that if_else from dplyr requires the true and false checks in the if_else command to be of same class and since there is no NA equivalent for class labelled (e.g. similar to NA_real_ for doubles), the code probably fails, right?

So, how can I recode my inital variables and preserve the labels?

I know I could change my code above and replace the if_else by R's base version ifelse. However, this deletes all labels and coerces the value column to a numeric one.

deschen
  • 2,415
  • 2
  • 13
  • 25
  • Try `dat %>% mutate_all(as_factor) %>% mutate(value = if_else(group != 'first', NA_character_, as.character(value)))` – akrun Apr 28 '20 at 20:57
  • Thanks. Using as_factor is probably the closest you can get, because it preserves at least the value labels. However, it still deletes a) the column label (the "label" part in my code) as well as the numeric representation of each code (i.e. the 0s and 1s). – deschen Apr 28 '20 at 21:06
  • You could create as a new 'value' column while preserving the original 'value' as such i.e. `dat %>% mutate_all(as_factor) %>% mutate(value2 = if_else(group != 'first', NA_character_, as.character(value)))` – akrun Apr 28 '20 at 21:07

2 Answers2

1

You can create an NA value in the haven_labelled class with this ugly code:

haven::labelled(NA_real_, labels = attr(dat$value, "labels"))

I'd recommend writing a function for that, e.g.

labelled_NA <- function(value) 
  haven::labelled(NA_real_, labels = attr(value, "labels"))

and then the code for your mutate isn't quite so ugly:

dat_new <- dat %>%
  mutate(value = if_else(group != labelled_NA(value), value)) 

Then you get

> 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]
user2554330
  • 22,664
  • 3
  • 23
  • 57
  • Thanks. I thought about creating a haven labelled object as well but wasn't sure how to do that. – deschen Apr 29 '20 at 08:32
1

You can try dplyr::case_when for cases where group == 1. If no cases are matched, NA is returned:

dat %>% mutate(value = case_when(group == 1 ~ value))
HNSKD
  • 1,378
  • 1
  • 11
  • 22