R - 避免嵌套for循环

时间:2015-09-30 01:05:43

标签: arrays r

我有以下功能,需要4个向量。 T向量具有给定长度,并且所有其他3个向量(pga,Sa5Hz和Sa1Hz)具有给定(相同但不一定等于T)的长度。

输出是一个长度为(T)行和长度(pga)列的矩阵。

下面的代码似乎是不做的完美示例,但是,我无法找到使用apply函数优化它的方法。有人可以帮忙吗?

designSpectrum <- function (T, pga, Sa5Hz, Sa1Hz){

  Ts <- Sa1Hz / Sa5Hz

  #By convention, if Sa5Hz is null, set Ts as 0.
  Ts[is.nan(Ts)] <- 0

  res <- matrix(NA, nrow = length(T), ncol = length(pga))

  for (i in 1:nrow(res))
  {
    for (j in 1:ncol(res))
    {
      res[i,j] <- if(T[i] <= 0) {pga[j]}
                  else if (T[i] <= 0.2 * Ts[j]) {pga[j] + T[i] * (Sa5Hz[j] - pga[j]) / (0.2 * Ts[j])}
                  else if (T[i] <= Ts[j]) {Sa5Hz[j]}
                  else Sa1Hz[j] / T[i]
      }
  }

  return(res)
}

1 个答案:

答案 0 :(得分:0)

您可以使用for函数一次性处理所有这些值,而不是执行双i循环并分别处理每个jouter值。由于您现在同时处理多个ij值,因此您可以切换到向量化ifelse语句,而不是非向量化ifelse语句:

designSpectrum2 <- function (T, pga, Sa5Hz, Sa1Hz) {
  Ts <- Sa1Hz / Sa5Hz
  Ts[is.nan(Ts)] <- 0
  outer(1:length(T), 1:length(pga), function(i, j) {
    ifelse(T[i] <= 0, pga[j],
      ifelse(T[i] <= 0.2 * Ts[j], pga[j] + T[i] * (Sa5Hz[j] - pga[j]) / (0.2 * Ts[j]),
        ifelse(T[i] <= Ts[j], Sa5Hz[j], Sa1Hz[j] / T[i])))
  })
}
identical(designSpectrum(T, pga, Sa5Hz, Sa1Hz), designSpectrum2(T, pga, Sa5Hz, Sa1Hz))
# [1] TRUE

数据:

T <- -1:3
pga <- 1:3
Sa5Hz <- 2:4
Sa1Hz <- 3:5

你可以通过测试相当大的向量来看到效率提升(这里我将使用一个包含100万个条目的输出矩阵):

# Larger vectors
set.seed(144)
T2 <- runif(1000, -1, 3)
pga2 <- runif(1000, -1, 3)
Sa5Hz2 <- runif(1000, -1, 3)
Sa1Hz2 <- runif(1000, -1, 3)

# Runtime comparison
all.equal(designSpectrum(T2, pga2, Sa5Hz2, Sa1Hz2), designSpectrum2(T2, pga2, Sa5Hz2, Sa1Hz2))
# [1] TRUE
system.time(designSpectrum(T2, pga2, Sa5Hz2, Sa1Hz2))
#    user  system elapsed 
#   4.038   1.011   5.042 
system.time(designSpectrum2(T2, pga2, Sa5Hz2, Sa1Hz2))
#    user  system elapsed 
#   0.517   0.138   0.652 

outer的方法快了近10倍。