【问题标题】:sapply() and ifelse() in RR 中的 sapply() 和 ifelse()
【发布时间】:2014-11-25 14:54:21
【问题描述】:

我遇到了一个问题,将嵌套的 sapply 粘贴代码包装到 ifelse() 中,检查所有组件是否都是非 NA。当 sapplys 不在 ifelse() 中时,它们工作得很好……这是为什么呢?

给定一些参数:

a = c(1, 2, 3)
b = c("a", "b")
c = c("X", "Y")

这是我设法将所有组合粘贴在一起的方法

as.vector(sapply(sapply(a, function(x){paste(x, b, sep = "")}), 
                 function(x){paste(x, c, sep = "")}))

输出是这样的。这正是我想要的:

[1] "1aX" "1aY" "1bX" "1bY" "2aX" "2aY" "2bX" "2bY" "3aX" "3aY" "3bX" "3bY"

但是,如果我将 完全相同的代码放入 ifelse() 中,以确保参数不是 NA,则输出会有所不同。

ifelse(!is.na(a) & !is.na(b) & !is.na(c), 
       as.vector(sapply(sapply(a, function(x){paste(x, b, sep = "")}), 
                                  function(x){paste(x, c, sep = "")})), "Error")
[1] "1aX" "1aY" "1bX"

Warning messages:
1: In !is.na(a) & !is.na(b) :
  longer object length is not a multiple of shorter object length
2: In !is.na(a) & !is.na(b) & !is.na(c) :
  longer object length is not a multiple of shorter object length

为什么?很明显,a、b、c 是不同的长度;我不明白为什么这在 ifelse() 中很重要。澄清一下, !is.na() 正在检查 whole vector 是否为 NA,而不是像 c(1, NA, 3) 这样的东西,因为我将在永远不会发生的上下文。我这样做是因为 ifelse 是较大函数的一部分,其中参数默认为 NA;非 NA 参数的某些组合需要某些操作。例如,如果 b = NA,那么上面的代码应该会产生一个错误。如何同时完成嵌套粘贴和条件检查?

【问题讨论】:

  • 有什么关系?您在那里使用&....您是否可能正在寻找any 与您的is.na 一起使用?
  • "如果 a 不是 NA,b 不是 NA,c 不是 NA,则像这样粘贴在一起。否则,给出错误。"在我较大的函数中默认为 a、b 和 c,默认为 NA。因此,如果用户不提供 a、b 或 c 的替代值,则 !is.na(a) = FALSE
  • 请在至少一个NA的一个或多个向量中提供至少一个值,并显示您对sapply调用的期望输出。
  • 请注意NA适用于向量的元素,而不是向量本身。 is.na 函数检查向量的每个元素是否为NA。另一方面,对象可以是NULL。也许您应该将您的对象初始化为NULL 而不是NA(并使用is.null 函数)。

标签: r if-statement sapply


【解决方案1】:

老实说,在这种情况下,我不会使用ifelse,而是分别使用ifelse 组件。 ifelse 仅返回与您的测试形状相同的值(因此您的初始输出仅提供 3 个输出),正如您在 this question 中所解释的那样。我想不出简洁的方法来测试所有组合,而不需要一些正则表达式,这似乎只不过是一种不必要的复杂性。以下应该可以正常工作。

if(!any(is.na(c(a,b,c)))){
  as.vector(sapply(sapply(a, function(x){paste(x, b, sep = "")}), 
                   function(x){paste(x, c, sep = "")}))
}else{
  "Error"
}

【讨论】:

    【解决方案2】:

    ifelse 对向量进行元素检查,并在“条件”为“TRUE”或“FALSE”的特定位置分别使用“then”和“else”情况下的相应值。例如,您可以使用ifelse 将向量中的每个负元素替换为位置值:

     d <- c(1, -1, 2, -2, 3, -3)
     order <- seq_along(d)
     ifelse(d < 0, order, d)
     # [1] 1 2 2 4 3 6
    

    所以d 的第一个元素不符合标准,所以它被d 的第一个元素替换。然而,第二个元素确实符合标准,因此它被order 的第二个元素替换,依此类推。这就是为什么所有向量都应该是等长的,如果不是,R 会使用它的回收技术。

    所以你要做的就是使用一个简单的if 语句

    a <- c(1, 2, 3)
    b <- c("a", "b")
    d <- c("X", "Y")
    if (all(!is.na(c(a, b, d))))  
        as.vector(sapply(sapply(a, function(x){paste(x, b, sep = "")}), 
                                     function(x) {paste(x, d, sep = "")})) else 
        "Error"
    # [1] "1aX" "1aY" "1bX" "1bY" "2aX" "2aY" "2bX" "2bY" "3aX" "3aY" "3bX" "3bY"
    
    d <- NA
    if (all(!is.na(c(a, b, d))))  
        as.vector(sapply(sapply(a, function(x){paste(x, b, sep = "")}), 
                                     function(x) {paste(x, d, sep = "")})) else 
        "Error"
    # [1] "Error"
    

    但是,您的代码难以阅读,您可以通过以下代码提高可读性:

    a <- c(1, 2, 3)
    b <- c("a", "b")
    d <- c("X", "Y")
    if (all(!is.na(c(a, b, d)))) apply(expand.grid(a, b, d), 1, paste, collapse = "") else "Error"
    # [1] "1aX" "2aX" "3aX" "1bX" "2bX" "3bX" "1aY" "2aY" "3aY" "1bY" "2bY" "3bY"
    
    d <- NA
    if (all(!is.na(c(a, b, d)))) apply(expand.grid(a, b, d), 1, paste, collapse = "") else "Error"
    # [1] "Error"
    

    expand.grid 创建三个向量的所有组合。 apply 贯穿所有行(这是第一个维度,这就是为什么 1 作为第二个参数来应用,然后将paste 应用到每一行。

    希望对您有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-11
      • 1970-01-01
      • 2013-10-10
      相关资源
      最近更新 更多