【问题标题】:nested ifelse() is the worst; what's the best? [duplicate]嵌套的 ifelse() 是最差的;什么是最好的? [复制]
【发布时间】:2015-05-06 22:39:00
【问题描述】:

编辑:这是How to implement coalesce efficiently in R 的骗子,同意。我没有意识到我的问题比我的具体应用更普遍,所以这次讨论很棒。

有时,随机实验中的响应变量包含在每个实验组的不同列中(以下代码中的 Y_1 到 Y_5)。通常最好将响应变量收集到单个列 (Y_all) 中。我最终按照下面的示例进行操作。但我确信有更好的方法。想法?

set.seed(343)
N <- 1000
group <- sample(1:5, N, replace=TRUE)
Y_1 <- ifelse(group==1, rbinom(sum(group==1), 1, .5), NA)
Y_2 <- ifelse(group==2, rbinom(sum(group==2), 1, .5), NA)
Y_3 <- ifelse(group==3, rbinom(sum(group==3), 1, .5), NA)
Y_4 <- ifelse(group==4, rbinom(sum(group==4), 1, .5), NA)
Y_5 <- ifelse(group==5, rbinom(sum(group==5), 1, .5), NA)

## This is the part I want to make more efficient
Y_all <- ifelse(!is.na(Y_1), Y_1, 
                ifelse(!is.na(Y_2), Y_2, 
                       ifelse(!is.na(Y_3), Y_3, 
                              ifelse(!is.na(Y_4), Y_4, 
                                     ifelse(!is.na(Y_5), Y_5, 
                                            NA)))))

table(Y_all, Y_1, exclude = NULL)
table(Y_all, Y_2, exclude = NULL)

【问题讨论】:

  • 对于这个特定的应用程序,找到第一个非缺失值,SQL命令的名称是coalesce,有一个很好的答案implementing SQL's coalesce in R
  • 请使用set.seed
  • Gregor,就是这样:我以前从未遇到过Reduce
  • 对于这种特殊情况,我想我有一个更快的方法:rowMeans( cbind(Y_1,Y_2,Y_3,Y_4,Y_5), na.rm=TRUE)rowSums 如果可以确保每个“行”最多有 1 个项目,那也可以。

标签: r if-statement


【解决方案1】:

我喜欢为此使用coalesce() 函数

#available from https://gist.github.com/MrFlick/10205794
coalesce<-function(...) {
    x<-lapply(list(...), function(z) {if (is.factor(z)) as.character(z) else z})
    m<-is.na(x[[1]])
    i<-2
    while(any(m) & i<=length(x)) {
        if ( length(x[[i]])==length(x[[1]])) {
            x[[1]][m]<-x[[i]][m]
        } else if (length(x[[i]])==1) {
            x[[1]][m]<-x[[i]]
        } else {
            stop(paste("length mismatch in argument",i," - found:", length( x[[i]] ),"expected:",length( x[[1]] ) ))
        }
        m<-is.na(x[[1]])
        i<-i+1
    }
    return(x[[1]])
}

那你就可以了

Y_all <- coalesce(Y_1,Y_2,Y_3,Y_4,Y_5)

当然,这对于获取第一个非 NA 值非常具体。

【讨论】:

  • 感谢 Flick 先生 -- 您是否更喜欢这种实现而不是 stackoverflow.com/questions/19253820/… 中的实现?
  • 没有。您必须进行测试,看看在您的特定应用程序中什么是最好的。
  • 这个实现很好,因为它有因子转换和错误处理——其他的还比较简单。
【解决方案2】:

我认为在这种情况下您可以使用 melt 函数将数据转换为长格式,然后摆脱缺失值:

library(reshape2)

set.seed(10)
N <- 1000
group <- sample(1:5, N, replace=TRUE)
Y_1 <- ifelse(group==1, rbinom(sum(group==1), 1, .5), NA)
Y_2 <- ifelse(group==2, rbinom(sum(group==2), 1, .5), NA)
Y_3 <- ifelse(group==3, rbinom(sum(group==3), 1, .5), NA)
Y_4 <- ifelse(group==4, rbinom(sum(group==4), 1, .5), NA)
Y_5 <- ifelse(group==5, rbinom(sum(group==5), 1, .5), NA)

Y_all = data.frame(group, Y_1, Y_2,Y_3,Y_4,Y_5)

Y_all.m = melt(Y_all, id.var="group")
Y_all.m = Y_all.m[!is.na(Y_all.m$value),]

【讨论】:

  • identical(Y_all,Y_all.m$value) 应该是真的吗?结果似乎已重新排序,因此情况并非如此。嗯,identical(Y_all,Y_all.m$value[order(rownames(Y_all.m))]) 同上
  • Y_all.m 是 Y_all 的长版本,因此它们不会完全相同。但是您可以确认它们具有相同的值,如下所示:lapply(Y_all[,-1], table, exclude=NULL); tapply(Y_all.m$value, Y_all.m$variable, table, exclude=NULL)
  • 我刚想到你也可以这样做:identical(unname(unlist(Y_all[,-1])), Y_all.m$value)(产生TRUE)。
  • 抱歉——我的意思是 OP 的 Y_all(不是您在此处给出的同名的 data.frame),我认为它是所需的输出。我可以在您的结果with(Y_all.m,table(value,variable));table(Y_all,group) 中看到计数是正确的,但我没有看到与 OP 的Y_all 对应的内容;就这样。我想念melt 为你做的事情。
【解决方案3】:

将向量存储在矩阵中,然后选择:

Ymat    <- cbind(Y_1,Y_2,Y_3,Y_4,Y_5)
mycol   <- apply(!is.na(Ymat),1,which)

Y_all.f <- Ymat[cbind(1:nrow(Ymat),mycol)]

identical(Y_all,Y_all.f) # TRUE

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-22
    • 1970-01-01
    相关资源
    最近更新 更多