缩短嵌套ifelse

use*_*689 3 if-statement r data.table

如果给出以下数据表,并且我们希望将x1与x2和x5进行比较,则可以使用以下数据:

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))))]
Run Code Online (Sandbox Code Playgroud)

所以,如果x1 < x2,然后compare == 1,等

现在在我的例子中,我有更多的列来比较x1和.有没有办法更简洁地写这个,即没有嵌套的ifelse?

akr*_*run 5

我们可以使用Mapmax.col使用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
Run Code Online (Sandbox Code Playgroud)

  • 我想`Map()`/`max.col()`/`Reduce`的一个更清晰的替代方法是使用一个简单而灵活的循环 - 比如`compare = rep_len(length(TDT),nrow(TDT) ); for(i in length(TDT):2)比较[TDT [[i]]> TDT [[1]]] = i - 1L`看起来有效 (3认同)

小智 5

这样可以节省一些打字并且易于阅读.

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

如果您有这么多列,您不想通过名称提及它们,那么您可以使用:

apply(TDT, 1, function (x) which(x[1] < x[2:5])[1]) 
Run Code Online (Sandbox Code Playgroud)

其中x [2:5]应由相关的列集替换.