Home > OS >  Create a variable with exclusive conditions in R
Create a variable with exclusive conditions in R

Time:05-24

My data look like this

Q3A1<-c(0,1,0,1,1,1,0,1,0,1)
Q3A2<-c(0,1,1,1,0,1,0,0,0,1)
Q3A3<-c(1,1,0,1,0,1,0,0,0,1)

And I would like to create a new variable Q3L were it is coded as 1 when Q1A1, Q1A2 and Q1A3 are all equal to 1

I tried this

dataQ$Q3L <- ifelse(dataQ$Q3A1==1|dataQ$Q3A2==1|dataQ$Q3A3==1, 1, 0 )

but It seemslike it is recoding as 1 if at least one of the three equal 1, but I need the tree of them to be equal to 1

I tried this as well

library(dplyr)
dataQ %>%
  mutate(Q3L = case_when(Q3A1 == 1 & Q3A2 == 1 & Q3A3 == 1 ~ 1,))

not a success neither

CodePudding user response:

We can use if_all - by looping over the columns that starts_with 'Q3A' in column names, create a logical condition to check whether the column values are 1 (.x == 1), if_all returns TRUE only when all of the columns for a row are TRUE i.e. all 1, then coerce the logical (TRUE/FALSE) to binary with or as.integer

library(dplyr)
dataQ <- dataQ %>% 
   mutate(Q3L =  (if_all(starts_with('Q3A'), ~ .x== 1)))

NOTE: Using | or & on a variable number of columns can be cumbersome, instead using either if_all or create the logical with rowSums

data

dataQ <- data.frame(Q3A1, Q3A2, Q3A3)

CodePudding user response:

You can do this:

dataQ["Q3L"] =  (dataQ$Q3A1 & dataQ$Q3A2 & dataQ$Q3A3)

Output:

   Q3A1 Q3A2 Q3A3 Q3L
1     0    0    1   0
2     1    1    1   1
3     0    1    0   0
4     1    1    1   1
5     1    0    0   0
6     1    1    1   1
7     0    0    0   0
8     1    0    0   0
9     0    0    0   0
10    1    1    1   1

CodePudding user response:

Update: thanks to input from @LMc: a more generalizable way would be:

library(dplyr)

tibble(Q3A1, Q3A2, Q3A3) %>% 
  mutate(Q3L = ifelse(select(., contains("Q3")) %>% 
                        rowSums() == ncol(.), 1, 0))

First answer:

We could check with rowSums and apply an ifelse statement:

library(dplyr)

tibble(Q3A1, Q3A2, Q3A3) %>% 
  mutate(Q3L = ifelse(select(., contains("Q3")) %>% 
                        rowSums() == 3, 1, 0))
    Q3A1  Q3A2  Q3A3   Q3L
   <dbl> <dbl> <dbl> <dbl>
 1     0     0     1     0
 2     1     1     1     1
 3     0     1     0     0
 4     1     1     1     1
 5     1     0     0     0
 6     1     1     1     1
 7     0     0     0     0
 8     1     0     0     0
 9     0     0     0     0
10     1     1     1     1

CodePudding user response:

library(dplyr)

df %>% 
  rowwise() %>% 
  mutate(Q3L = as.numeric(all(as.logical(c_across(starts_with("Q3")))))) %>% 
  ungroup()

Or with purrr::pmap_dbl

library(purrr)
library(dplyr)

df %>% 
  mutate(Q3L = pmap_dbl(across(starts_with("Q3")), ~ all(.x == 1)))

Or purrr::reduce

df %>% 
  mutate(Q3L = as.numeric(reduce(across(starts_with("Q3")), `&`)))

Output

    Q3A1  Q3A2  Q3A3   Q3L
   <dbl> <dbl> <dbl> <dbl>
 1     0     0     1     0
 2     1     1     1     1
 3     0     1     0     0
 4     1     1     1     1
 5     1     0     0     0
 6     1     1     1     1
 7     0     0     0     0
 8     1     0     0     0
 9     0     0     0     0
10     1     1     1     1

How it works

Both answers work similarly. They go row-by-row and convert the rows to logical vectors. all then tests if every element of the row-wise logical vector is TRUE. If it is then 1 is returned otherwise 0.

purrr::reduce works a bit differently. For each row it reduces the row-wise vector using the & function into a single logical value.

  • Related