2017-03-27 216 views
3

如果下面的数据表中给出的,我们愿与X2到X5因此比较X1时,可以使用下列:缩短嵌套ifelse

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

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

现在在我的例子中,我有更多的列来比较x1。有什么方法可以更简洁地编写,即没有嵌套ifelse?

+0

在你的例子中,它给出了所有FALSE,请提供一个例子,给出所有可能性 – akrun

+0

@akrun我编辑了这个例子。 – user3032689

+0

谢谢,由于较早的数据,我无法正确测试它。更新帖子 – akrun

回答

5

我们可以在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 
+0

@ user3032689 I改变了答案 – akrun

+3

我想'Map()'/'max.col()'/'Reduce'的一个更清晰的替代方法是使用一个简单而灵活的循环 - 例如比如'compare = rep_len(length(TDT),nrow(TDT));对于(我的长度(TDT):2)比较[TDT [[i]]> TDT [[1]]] = i - 1L'看起来有效 –

5

这样可以节省一点打字和易于阅读做到这一点使用Mapmax.col

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

如果你有,你不想点名他们都这么多列,那么你可以使用:

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

其中x [2:5]应由取代相关的一组列。

+0

我以前从来没有使用':='运算符。你能简单介绍一下它在这里的作用吗?基于在线文档,它不是很清楚... – patrick

+0

也没有I.一些有点疯狂'data.table'的东西。我认为它创造了一个新的专栏。 – dash2

+0

尽管感谢酷!我读了它[一点](https://cran.r-project.org/web/packages/data.table/vignettes/datatable-reference-semantics.html):_The:=运营商更新data.table在原地(通过引用)列_以避免在更换或重新分配部分数据集时避免任何形式的浅层或深层复制。您可以像这样使用它:'DT [,c(“colA”,“colB”,...):= list(valA,valB,...)]' – patrick