【问题标题】:How to automate operations between each columns of two matrices using R?如何使用 R 自动执行两个矩阵的每一列之间的操作?
【发布时间】:2016-08-02 21:02:40
【问题描述】:

我为 MAPE 编写了通用函数(平均绝对百分比误差)

mape <- function(y, yhat)
     mean(abs((y - yhat)/y))

我想计算两个不同矩阵的每一列之间的 MAPE。 假设它们采用以下格式

y = matrix(c(11, 12, 12, 12, 14, 16, 23, 21, 28),byrow=TRUE,ncol=3)

预测为

yp = matrix(c(12, 13, 14, 12, 15, 17, 24, 22, 28),byrow=TRUE,ncol=3)

这可以通过mape(y[,1],yp[,1])为每一列手动完成

如何使用 R 在大维矩阵的每一列之间执行操作的自动化过程(任何其他操作也 - 不仅是 MAPE)?使用 apply/sapply 可以避免 FOR 循环吗?

【问题讨论】:

  • 如果替代方案是使用apply 或sapply,您可以安全地使用for 循环,基本上没有任何缺点。用apply 替换循环不会加快速度。

标签: r for-loop matrix lapply sapply


【解决方案1】:

更新:

当然 mape 可以矢量化:

mapeVec <- function(y, yhat)
  colMeans(abs((y-yhat)/y))

f3 <- function() { mapeVec(y, yp) } 

Unit: milliseconds
 expr       min        lq      mean    median        uq      max neval cld
 f1() 33.677431 34.121107 35.494355 34.441823 35.078125 46.16782   100  b 
 f2() 33.558224 33.970123 35.609414 34.239525 34.881354 49.99195   100  b 
 f3()  8.344952  8.525146  9.218695  8.568763  8.709681 17.82791   100 a  

identical(f1(), f3())  # TRUE

旧部分:

sapply 与序列 seq(nrow(y)) 应该可以解决问题:

mape <- function(y, yhat)
  mean(abs((y - yhat)/y))

y <- matrix(c(11, 12, 12, 12, 14, 16, 23, 21, 28), nrow = 3, ncol = 3)

yp = matrix(c(12, 13, 14, 12, 15, 17, 24, 22, 28), nrow = 3, ncol = 3)

sapply(seq(nrow(y)), function(id) { mape(y[,id], yp[,id]) })

微基准测试:

library(microbenchmark)

mape <- function(y, yhat)
  mean(abs((y - yhat)/y))

y <- matrix(rnorm(1000000), nrow = 1000, ncol = 1000)

yp = matrix(rnorm(1000000), nrow = 1000, ncol = 1000)

f1 <- function() { sapply(seq(nrow(y)), function(id) { mape(y[,id], yp[,id]) }) }

f2 <- function() { 
  a <- vector(mode = "numeric", length = nrow(y))
  for(id in seq(nrow(y))) { 
    a[id] <- mape(y[,id], yp[,id]) 
  }
  a
}

microbenchmark(
  f1(),
  f2()
)

结果:

Unit: milliseconds
 expr      min       lq     mean   median       uq      max neval cld
 f1() 33.28310 34.15209 36.57389 35.42845 36.20803 48.11936   100   a
 f2() 34.14755 34.78859 37.65782 36.33395 37.06874 64.10664   100   a

个人评论:

f1(sapply() 方法)看起来更加紧凑和“干净”。

【讨论】:

  • 您可以将seq(1:dim(y)[1]) 替换为seq(nrow(y))。它不会改变任何东西,只是让长度的来源更加明显。
  • 已替换。无法抗拒:microbenchmark( seq(1:dim(y)[1]), seq(nrow(y)), times = 1000 ) 给出了10.82 与9.88 的平均值和9.87 与8.69 的中位数。
  • 那是因为你使用了seq(1:dim(y)[1]),即你基本上序列了两次。如果您改为使用seq(dim(y)[1]),您会得到完全相同的结果。如果您尝试优化速度,请改用seq_len。
猜你喜欢
  • 1970-01-01
  • 2016-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多