Search code examples
rdataframeif-statement

nested ifelse in R with "condition has length > 1" warning


I have the below data frame and would like to impose some rules to generate new values:

column_1<-c("B","B","B","B","A","A","A","A")
column_2<-c("L","L","B","B","L","L","B","B")
column_3<-c("c","b","c","b","c","b","c","b")
column_4<-rep(1)
column_5<-rep(0.5)
column_6<-rep(2)

df_test<-data.frame(column_1,column_2,column_3,column_4,column_5,column_6)
#concatenating column 1,2,3 as a flag, naming it column 7
df_test$column_7<-paste0(df_test$column_1,df_test$column_2,df_test$column_3)

> df_test
  column_1 column_2 column_3 column_4 column_5 column_6 column_7
1        B        L        c        1      0.5        2      BLc
2        B        L        b        1      0.5        2      BLb
3        B        B        c        1      0.5        2      BBc
4        B        B        b        1      0.5        2      BBb
5        A        L        c        1      0.5        2      ALc
6        A        L        b        1      0.5        2      ALb
7        A        B        c        1      0.5        2      ABc
8        A        B        b        1      0.5        2      ABb

#rule 1: if column_7=="BLc|BBb", then df_test$result will be equal to column 4 +column 5 +column_6
#rule 2: if column_7=="BLb|BBc", then df_test$result will be equal to column 4 +column 5 -column_6
#rule 3: if column_7=="ALc|ABb", then df_test$result will be equal to column 4 -column 5 -column_6
#rule 4: if column_7=="ABc|ALb", then df_test$result will be equal to column 4 -column 5 +column_6

To convert the rules, I have the below snippet:

df_test$result<-if(df_test$column_7=="BLc|BBb"){
  df_test$column_4+df_test$column_5+df_test$column_6
}else{
  if(df_test$column_7=="BLb|BBc"){
    df_test$column_4+df_test$column_5-df_test$column_6
  }else{
    if(df_test$column_7=="ALc|ABb"){
      df_test$column_4-df_test$column_5-df_test$column_6
    } else{
      if(df_test$column_7=="ABc|ALb"){
        df_test$column_4-df_test$column_5+df_test$column_6
      }
    }
  }
}

Warning messages:
1: In if (df_test$column_7 == "BLc|BBb") { :
  the condition has length > 1 and only the first element will be used
2: In if (df_test$column_7 == "BLb|BBc") { :
  the condition has length > 1 and only the first element will be used
3: In if (df_test$column_7 == "ALc|ABb") { :
  the condition has length > 1 and only the first element will be used
4: In if (df_test$column_7 == "ABc|ALb") { :
  the condition has length > 1 and only the first element will be used

> print(df_test$result)
NULL

Here I assume the way I nest with if else goes wrong, can you please give me some hints on it?

If everything goes right, the below is expected to be seen:

> data.frame(desired_column_8)
  desired_column_8
1              3.5
2             -0.5
3             -0.5
4              3.5
5             -1.5
6              2.5
7              2.5
8             -1.5

Anyway, thanks all for taking time to view this post.

Update 1: Try dplyr::case_when

library(dplyr)
df_test<-df_test %>%
  mutate(column_8=case_when(column_7=="BLc|BBb" ~df_test$column_4+df_test$column_5+df_test$column_6,
                            column_7=="BLb|BBc" ~df_test$column_4+df_test$column_5-df_test$column_6,
                            column_7=="ALc|ABb" ~df_test$column_4-df_test$column_5-df_test$column_6,
                            column_7=="ABc|ALb"~df_test$column_4-df_test$column_5+df_test$column_6))


> df_test
  column_1 column_2 column_3 column_4 column_5 column_6 column_7 column_8
1        B        L        c        1      0.5        2      BLc       NA
2        B        L        b        1      0.5        2      BLb       NA
3        B        B        c        1      0.5        2      BBc       NA
4        B        B        b        1      0.5        2      BBb       NA
5        A        L        c        1      0.5        2      ALc       NA
6        A        L        b        1      0.5        2      ALb       NA
7        A        B        c        1      0.5        2      ABc       NA
8        A        B        b        1      0.5        2      ABb       NA
> 

Solution

  • An option using match. It may be more performant than nested ifelses.

    codes <- c("BLc", "BBb", "BLb", "BBc", "ABc", "ALb", "ALc", "ABb")
    transform(
      df_test,
      result = {
        i <- (match(column_7, codes) - 1)%/%2
        column_4 + column_5*(1 - 2*(i%/%2)) + column_6*(1 - 2*(i%%2))
      }
    )
    #>   column_1 column_2 column_3 column_4 column_5 column_6 column_7 result
    #> 1        B        L        c        1      0.5        2      BLc    3.5
    #> 2        B        L        b        1      0.5        2      BLb   -0.5
    #> 3        B        B        c        1      0.5        2      BBc   -0.5
    #> 4        B        B        b        1      0.5        2      BBb    3.5
    #> 5        A        L        c        1      0.5        2      ALc   -1.5
    #> 6        A        L        b        1      0.5        2      ALb    2.5
    #> 7        A        B        c        1      0.5        2      ABc    2.5
    #> 8        A        B        b        1      0.5        2      ABb   -1.5