计算向量内的每个值,并将结果汇​​总到向量

时间:2019-04-15 16:12:30

标签: r

我有一个问题,我需要对向量进行一些操作,对于向量内的每个值,我需要根据给定的上升范围L,为该值计算“上升”值。

例如,在10位置的值3rd,加速功能将返回[2.5, 5],该值应该是该值{{1}的加速值},它们位于10的位置。

我想要的结果是一个单一向量,它也是一个向量,但具有所有加速效果。

我已经使用了一些方法来成功获得正确的结果。

因为我需要做很多这样的操作,所以我想知道是否有更快的方法来实现它。 (profvis显示此操作是我脚本的瓶颈)

这是一个简单的例子

1st, 2nd
x = c(0, 0, 5, 10, 10, 20, 10)
L = 2

r = matrix(0, L, length(x))
for(i in 1: L)
{
       r[i, ] = map(x, ramp, L) %>% 
                map_dbl(i) %>% 
                lead(L-i+1, default = 0)
}

结果矩阵r [,1] [,2] [,3] [,4] [,5] [,6] [,7] [1,] 1.250000 2.500000 2.500000 5.000000 2.500000 0.000000 0 [2,] 0.000000 2.500000 5.000000 5.000000 10.000000 5.000000 0 的第一行是移到正确位置后的第一个加速值,第二行是第二个加速值。

我想要的最终返回向量是

r

任何建议都值得欢迎,谢谢。

为清楚起见,这是我使用的colSums(r) 函数,半斜坡只是为了易于理解的示例。

ramp()

这是结果

ramp <- function(Value, Len, R = 0.5)
{
  out <- c(1:(Len+1)) 
  if(R != 0) { out <- exp(R*c(1:(Len+1)))*Value/exp(R*(Len+1)) } 
  else { out <- c(rep(0, Len), Value) } 
  return(out)
}

x = c(0, 0, 5, 10, 10, 20, 10)
L = 2

r = matrix(0, L, length(x))
for(i in 1: L)
{
   r[i, ] = map(x, ramp, L) %>% map_dbl(i) %>% lead(L-i+1, default = 0)
}
r
         [,1]     [,2]     [,3]     [,4]      [,5]     [,6] [,7]
[1,] 1.839397 3.678794 3.678794 7.357589  3.678794 0.000000    0
[2,] 0.000000 3.032653 6.065307 6.065307 12.130613 6.065307    0

1 个答案:

答案 0 :(得分:0)

到目前为止,我想发表一些尝试来提高流程效率。

我要做的第一件事是优化我的ramp.all()步骤,这是我的示例脚本的第二部分。

ramp.all.old.1 <- function(x, L)
{
  r = rep(0, length(x))
  for(i in 1: L)
  {
    r = rbind(r, map(x, ramp, L) %>% map_dbl(i) %>% lead(L-i+1, default = 0))
  }
  return(colSums(r))
}

当我阅读其他文章时,我注意到rbind()可能不是达到我目的的最佳选择。因此,第一个尝试是预先分配结果矩阵r,所以我得到了第二个版本。

ramp.all.old.2 <- function(x, L)
{
   r = matrix(0, L, length(x))
   for(i in 1: L)
   {
       r[i, ] = map(x, ramp, L) %>% map_dbl(i) %>% lead(L-i+1, default = 0)
   }
   return(colSums(r))
}

然后,当我仔细查看循环中的代码时,我注意到map()实际上是多余的,它只需要在循环之前计算一次即可。因此我将map()移出,并用lapply()代替。

ramp.all.old.3 <- function(x, L)
{
  r = matrix(0, L, length(x))
  tmp = lapply(x, ramp, L)
  for(i in 1: L)
  {
      r[i, ] = tmp %>% map_dbl(i) %>% lead(L-i+1, default = 0)
  }
  return(colSums(r))
}  

类似地,map_dbl()似乎没有经过优化,还有更好的方法。因此,我推出了版本4。

ramp.all.old.4 <- function(x, L)
{
  r = matrix(0, L, length(x))
  tmp = as.data.frame(data.table::transpose(lapply(x, ramp, L)), col.names = letters[1:(L+1)])
  for(i in 1: L)
  {
    r[i, ] = lead(tmp[, i], L-i+1, default = 0)
  }
  return(colSums(r))
}  

正如@Gregor所建议的那样,加速ramp()函数在这里也很重要。我想出了一种更改ramp()函数的方法,该函数现在可以利用 out-product 操作将 vector 作为输入。我想出了ramp.new()函数

ramp.new <- function(Value, Len, R = 0.5)
{
   out = Value %*% t(exp(R*c(1:(Len+1)))/exp(R*(Len+1))) 
   return(out)
}

新的ramp.all()函数是

ramp.all <- function(x, L)
{
   r = matrix(0, L, length(x))
   tmp = ramp.new(x, L)
   for(i in 1: L)
   {
     r[i, ] = lead(tmp[, i], L-i+1, default = 0)
   }
   return(colSums(r))
}

这是性能测试结果。

x
[1]  0  0  5 10 10 20 10
microbenchmark(ramp.all.old.1(x, 2)->res.1, ramp.all.old.2(x, 2)->res.2, ramp.all.old.3(x, 2)->res.3, ramp.all.old.4(x, 2)->res.4,ramp.all(x, 2)->res.5)
Unit: microseconds
                          expr     min       lq     mean  median       uq      max neval  cld
 res.1 <- ramp.all.old.1(x, 2) 529.461 565.0145 603.9836 589.810 618.7990  816.800   100    d
 res.2 <- ramp.all.old.2(x, 2) 526.909 565.1965 619.6961 590.357 623.7215 1684.649   100    d
 res.3 <- ramp.all.old.3(x, 2) 441.582 472.0305 512.1629 500.655 525.0860  859.463   100   c 
 res.4 <- ramp.all.old.4(x, 2) 299.736 331.4610 375.3600 350.422 385.7930 1232.857   100  b  
       res.5 <- ramp.all(x, 2)  34.277  47.7680  56.4947  50.504  56.3385  137.470   100 a   
identical(res.1, res.2, res.3, res.4, res.5)
[1] TRUE

到目前为止,我还很高兴。检查profvis,看来我下一步应该专注于lead()函数。

欢迎其他任何建议,谢谢@ akrun,@ Gregor。