首页 > 解决方案 > 使用 if 条件修改 for 循环以在 R 中应用格式

问题描述

我正在创建一个名为 indexPoints 的变量,其中包含通过某些条件的索引值的子集 -

set.seed(1)
x = abs(rnorm(100,1))
y = abs(rnorm(100,1))
threshFC = 0.5

indexPoints=c()
seqVec = seq(1, length(x))
for (i in seq_along(seqVec)){
    fract = x[i]/y[I]
    fract[1] = NaN
    if (!is.nan(fract)){
        if(fract > (threshFC + 1) || fract < (1/(threshFC+1))){
            indexPoints = c(indexPoints, i)
        }
    }
}

我正在尝试使用更有效的方法重新创建 indexPoints,例如应用方法(除了 sapply 之外的任何方法)。我开始了如下所示的过程 -

set.seed(1)
x = abs(rnorm(100,1))
y = abs(rnorm(100,1))
threshFC = 0.5

seqVec <- seq_along(x)
fract = x[seqVec]/y[seqVec]
fract[1] = NaN
vapply(fract, function(i){
    if (!is.nan(fract)){ if(fract > (threshFC + 1) || fract < (1/(threshFC+1))){ i}}
}, character(1))

但是,此尝试会导致错误:

Error in vapply(fract, function(i) { : values must be length 1,
 but FUN(X[[1]]) result is length 0

如何继续修改代码以使其成为应用格式。注意:有时,fract 变量包含 NaN 值,我通过使用“fract[1] = NaN”来模仿上面的最小示例。

标签: rlapply

解决方案


您的代码有几个问题:

  1. 您告诉vapply您希望内部代码返回 a character,但您返回的唯一i内容是numeric;
  2. 只有当所有条件都满足时,你才显式地返回一些东西,这意味着如果条件不是很好,你什么都不返回......这与return(NULL)which is also not character(try vapply(1:2, function(a) return(NULL), character(1)));
  3. 你明确地设置fract[1] = NaN然后测试!is.nan(fract),所以你永远不会得到任何东西;和
  4. (可能是错字)您引用y[I](大写“i”)这是一个错误,除非I在某处定义(这不再是语法错误,但现在是逻辑错误)。

如果我修复循环NaN中的代码(删除分配) ,我会得到for

indexPoints
#  [1]  3  4  5  6 10 11 12 13 14 15 16 18 20 21 25 26 28 29 30 31 32 34 35 38 39
# [26] 40 42 43 44 45 47 48 49 50 52 53 54 55 56 57 58 59 60 61 64 66 68 70 71 72
# [51] 74 75 77 78 79 80 81 82 83 86 88 89 90 91 92 93 95 96 97 98 99

如果我们真的想一次做一个(我建议不要这样做,请阅读下文),那么有几种方法:

  1. 用于Filter仅返回条件为真的索引:

    indexPoints2 <- Filter(function(i) {
      fract <- x[i] / y[i]
      !is.nan(fract) && (fract > (threshFC+1) | fract < (1/(threshFC+1)))
    }, seq_along(seqVec))
    identical(indexPoints, indexPoints2)
    # [1] TRUE
    
  2. vapply 正确使用,无论哪种方式都返回一个整数:

    indexPoints3 <- vapply(seq_along(seqVec), function(i) {
      fract <- x[i] / y[i]
      if (!is.nan(fract) && (fract > (threshFC+1) | fract < (1/(threshFC+1)))) i else NA_integer_
    }, integer(1))
    str(indexPoints3)
    #  int [1:100] NA NA 3 4 5 6 NA NA NA 10 ...
    indexPoints3 <- indexPoints3[!is.na(indexPoints3)]
    identical(indexPoints, indexPoints3)
    # [1] TRUE
    

    (注意特定类型的 NA 的显式返回,即NA_integer_,这vapply很高兴。)

  3. logical如果索引匹配条件,我们可以改为返回:

    logicalPoints4 <- vapply(seq_along(seqVec), function(i) {
      fract <- x[i] / y[i]
      !is.nan(fract) && (fract > (threshFC+1) | fract < (1/(threshFC+1)))
    }, logical(1))
    head(logicalPoints4)
    # [1] FALSE FALSE  TRUE  TRUE  TRUE  TRUE
    identical(indexPoints, which(logicalPoints4))
    # [1] TRUE
    

但实际上,绝对不需要使用vapply或任何apply函数,因为这可以很容易(并且更有效地)检查为向量:

fract <- x/y # all at once
indexPoints5 <- which(!is.nan(fract) & (fract > (threshFC+1) | fract < (1/(threshFC+1))))
identical(indexPoints, indexPoints5)
# [1] TRUE

(如果您不使用which,您会看到它为您提供了一个logical指示是否满足条件的向量,类似于上面的项目符号 3 logicalPoints4。)


推荐阅读