【问题标题】:Function for selecting even numbers in a vector in R在R中的向量中选择偶数的函数
【发布时间】:2020-08-12 12:52:00
【问题描述】:

我想创建一个函数,给定一个向量,报告另一个带有偶数的向量。

evens <- function(x){
  vector <- c()
  for (i in 1:length(x)){
    if (i %% 2 == 0){
      vector[i] <- vector[i] + i
    }
  }
  vector
}

但这会给 x 中的一个数字NULL

有人知道缺少什么吗? 谢谢

【问题讨论】:

  • x[ x %% 2 == 0] 是一种将数字向量x 简化为“偶数”值的方法。您的代码有两个问题:i %% 2 == 0 正在测试您的号码的 index 是否是偶数,而不是数字本身,您可能需要x[i] %% 2 == 0。其次,您的第一个vector[i]NA,因此将其添加到任何数字将始终是NA;另外,你不能保证有length(x) 的输出,所以分配给vector[i] 是有问题的。考虑单独跟踪您向vector 添加的元素数量,与i 分开。
  • 最后一点,我的意思是j &lt;- 0; for (i in 1:length(x)) { if (...) { j &lt;- j + 1; vector[j] &lt;- x[i]; } }; vector 或类似的东西。
  • 从 x 获取 偶数 的简短且可能 快速 的版本是 x[!x%%2]

标签: r function for-loop


【解决方案1】:

x 获取偶数 的一种简短且可能快速 的方法是x[!x%%2]

evens.HrantDavtyan <- function(x) x[lapply(x, "%%", 2) == 0]
evens.HrantDavtyan2 <- function(x){
  vector <- c()
  for (i in 1:length(x)){
    if (x[i] %% 2 == 0){ #this was the first error line
      vector <- c(vector, x[i]) ##this was the seconds error line
    }
  }
  vector
}
evens.AllanCameron <- function(x) subset(x, x %% 2 == 0)
evens.r2evans <- function(x) x[ x %% 2 == 0]
evens.GKi <- function(x) x[!x%%2]
x <- 1:10000
microbenchmark::microbenchmark(evens.HrantDavtyan(x), evens.HrantDavtyan2(x), evens.AllanCameron(x), evens.r2evans(x), evens.GKi(x), control=list(order="block"))
#Unit: microseconds
#                   expr       min         lq       mean     median         uq       max neval
#  evens.HrantDavtyan(x)  3163.272  3222.8030  3938.6202  3269.1015  3527.5345 33867.486   100
# evens.HrantDavtyan2(x) 26009.475 28061.4230 28196.7498 28275.5705 28794.2855 30856.206   100
#  evens.AllanCameron(x)   239.599   240.4480   257.7027   240.9265   243.7575  1715.947   100
#       evens.r2evans(x)   199.506   200.2945   202.1106   200.7690   203.7865   224.104   100
#           evens.GKi(x)   191.303   191.7400   193.2737   192.1310   193.2295   217.001   100

【讨论】:

  • 由于我们没有偏差/方差,很难说您的解决方案的速度是否与我的统计上不同 ;-)(我猜是这样,通过使用 iqr 作为 t 检验的代理进行猜测)
  • @r2evans GKi 的所有 100 次评估都快于您的中值,因此如果您使用 Mann-Whitney,它肯定具有统计学意义。当然,你们两个都比我快得多:我的结果甚至与你的结果不重叠......
  • 艾伦,这主要是讽刺,从岩石中挤出水。是的,它更快,甚至可以通过代码高尔夫获胜!我不会想到使用subset,但你的并没有落后太多。 *耸耸肩*无论如何,是的:-)
【解决方案2】:

我认为您可以简化此过程并大大加快速度:

evens <- function(x) subset(x, x %% 2 == 0)
evens(1:10)
#> [1]  2  4  6  8 10

使用lapply 可能不是一个好主意,因为它实际上在引擎盖下使用了循环。最好坚持使用 R 的原生向量化,从以下基准可以看出:

evens1 <- function(some_array) some_array[lapply(some_array, "%%", 2) == 0]
microbenchmark::microbenchmark(evens1(1:10000), evens(1:10000))
#> Unit: microseconds
#>             expr      min       lq      mean   median       uq       max neval cld
#>  evens1(1:10000) 5694.309 5883.195 6359.1855 6039.232 6306.992 14811.840   100   b
#>   evens(1:10000)  757.942  770.944  788.6802  785.317  799.346   912.267   100  a 

【讨论】:

    【解决方案3】:

    解决方案 1 您将更好地使用通常更快且更用户友好的应用功能。在您的情况下,它将是:

    some_array <- c(1,4,5,7,8)
    some_array[lapply(some_array, "%%", 2) == 0]
    

    上面的代码会将模数超过 2 函数应用于您的数组,并仅返回满足模数超过 2 == 0 条件的元素。

    解决方案 2 如果您仍然想使用您的方法,那么错误是您计算索引的提醒(并分别附加到数组)(即i)。相反,您应该对数组的元素执行此操作(即x[i])。 正确的代码是:

    evens <- function(x){
      vector <- c()
      for (i in 1:length(x)){
        if (x[i] %% 2 == 0){ #this was the first error line
          vector <- c(vector, x[i]) ##this was the seconds error line
        }
      }
      vector
    }
    

    【讨论】:

    • lapply 在向量上做“数学”真的是过度设计了。 (诚​​然,for 循环也是如此,但功课就是功课。)请注意(通常)“不断增长的对象”,即迭代地附加到向量(以及列表和框架)从长远来看会很差;参见R Inferno 的第 2 章,标题为“Growing Objects”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-25
    • 1970-01-01
    • 1970-01-01
    • 2012-07-31
    • 1970-01-01
    相关资源
    最近更新 更多