Shorten nested ifelse

梦想的初衷 提交于 2020-07-02 20:32:15

问题


If the following data table is given, and we would like to compare x1 consequently with x2 to x5, the following can be used:

set.seed(1)
library(data.table)
TDT <- data.table(x1 = round(rnorm(100,0.75,0.3),2),
                  x2 = round(rnorm(100,0.75,0.3),2),
                  x3 = round(rnorm(100,0.75,0.3),2),
                  x4 = round(rnorm(100,0.75,0.3),2),
                  x5 = round(rnorm(100,0.75,0.3),2))

TDT[,compare := ifelse(x1 < x2,1,ifelse(x1 < x3,2,ifelse(x1 < x4,3,ifelse(x1 < x5,4,5))))]

So if x1 < x2, then compare == 1, etc.

Now in my example, I have a lot more columns to compare x1 with. Is there any way to write this more concisely, i.e. without nested ifelse?


回答1:


We can do this using Map and max.col in data.table

TDT[, compare := {d1 <- as.data.table(Map(function(x) x1 < x, .SD))
       max.col(d1, "first") *(c(5, 1)[((Reduce(`+`, d1)!=0)+1)])}, .SDcols = x2:x5]

#OP's code
v1 <- TDT[, ifelse(x1 < x2,1,ifelse(x1 < x3,2,ifelse(x1 < x4,3,ifelse(x1 < x5,4,5))))]
identical(v1, TDT$compare)
#[1] TRUE



回答2:


This saves a bit of typing and is easy to read.

TDT[, compare := dplyr::case_when(
      x1 < x2 ~ 1,
      x1 < x3 ~ 2,
      x1 < x4 ~ 3,
      x1 < x5 ~ 4,
      TRUE ~ 5)]

If you have so many columns that you don't want to mention them all by name, then you could use:

apply(TDT, 1, function (x) which(x[1] < x[2:5])[1]) 

where x[2:5] should be replaced by the relevant set of columns.



来源:https://stackoverflow.com/questions/43045098/shorten-nested-ifelse

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!