【问题标题】:Add consecutive elements of a vector until a value将向量的连续元素相加直到一个值
【发布时间】:2011-12-17 08:34:04
【问题描述】:

我想计算向量中连续元素的最小数量,当添加(连续)时会小于给定值。

例如在下面的向量中

ev<-c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 2.7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.27, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 370.33, 1375.4, 
1394.03, 1423.8, 1360, 1269.77, 1378.8, 1350.37, 1425.97, 1423.6, 
1363.4, 1369.87, 1365.5, 1294.97, 1362.27, 1117.67, 1026.97, 
1077.4, 1356.83, 565.23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 356.83, 
973.5, 0, 240.43, 1232.07, 1440, 1329.67, 1096.87, 1331.37, 1305.03, 
1328.03, 1246.03, 1182.3, 1054.53, 723.03, 1171.53, 1263.17, 
1200.37, 1054.8, 971.4, 936.4, 968.57, 897.93, 1099.87, 876.43, 
1095.47, 1132, 774.4, 1075.13, 982.57, 947.33, 1096.97, 929.83, 
1246.9, 1398.2, 1063.83, 1223.73, 1174.37, 1248.5, 1171.63, 1280.57, 
1183.33, 1016.23, 1082.1, 795.37, 900.83, 1159.2, 992.5, 967.3, 
1440, 804.13, 418.17, 559.57, 563.87, 562.97, 1113.1, 954.87, 
883.8, 1207.1, 1046.83, 995.77, 803.93, 1036.63, 946.9, 887.33, 
727.97, 733.93, 979.2, 1176.8, 1241.3, 1435.6)

连续添加时(如向量中的顺序)的最小元素数量是多少,可以说是 20000

为了更清楚,我需要以下内容: 从 ev[1] 开始并连续添加到 20000。将您必须添加的元素数记录为 r[1] 才能达到 20000。然后从 ev[2] 开始并添加到 20000 等等。将在 20000 之前必须添加的元素数量记录为 r[2]。在 ev 的整个长度上执行此操作。然后返回 min(r)

例如

j&lt;-c(1, 2, 3, 5, 7, 9, 2).

我想要连续添加时的最少元素数,比如说 >20。这应该是3 (5+7+9)

非常感谢

【问题讨论】:

  • 这真的是重复的:stackoverflow.com/questions/8539303/…
  • 不,不是。它只是试图解决一些问题并回答我以前的问题
  • 你不想找到总和为 20000 的最小连续数字序列吗?考虑c(1,2,19999,0,0,55)。您所说的算法会回答 3 (1,2,19999) 而不是 2 (2,19999)?
  • Tommy:在你提到的例子中,答案是 2。你能帮我编程吗?
  • @ECII - 好吧,因为现在是星期五 ;-)

标签: r


【解决方案1】:

好吧,我试一试:这个会找到最小数字序列的长度 加起来等于或高于max。它没有声称很快,但它具有O(2n) 时间复杂度:-)

我让它返回起始索引和长度。

f <- function(x, max=10) {
  s <- 0
  len <- Inf
  start <- 1
  j <- 1
  for (i in seq_along(x)) {
     s <- s + x[i]
     while (s >= max) {
       if (i-j+1 < len) {
         len <- i-j+1
         start <- j
       }
       s <- s - x[j]
       j <- j + 1
     }
  }

  list(start=start, length=len)
  # uncomment the line below if you don't need the start index...
  #len
}

r <- f(ev, 20000) # list(start=245, length=15)
sum(ev[seq(r$start, len=r$length)]) # 20275.42

# Test speed:
x <- sin(1:1e6)

system.time( r <- f(x, 1.9) ) # 1.54 secs

# Compile the function makes it 9x faster...
g <- compiler::cmpfun(f)
system.time( r <- g(x, 1.9) ) # 0.17 secs

【讨论】:

  • @Dason 和 ECII - 谢谢,但这只是一个 for 循环 ;-)
  • @Tommy 是否可以修改函数,使其可以接收一个值向量作为最大值并输出对应于每个最大值的值向量?
【解决方案2】:
library(zoo) # Needed for rollapply
N <- 20000 # The desired sum we want to achieve
j <- 0
for(i in 1:length(ev)){
    k <- rollapply(ev, i, sum)
    j[i] <- max(k)
    if(j[i] >= N){
        break
    }
}
i # contains how many consecutive elements you need to sum (15)
j[i] # contains the corresponding sum(20275.42)

目前,这并不能告诉您特定子集在向量中的位置,但 rollapply 的另一种用法可以为您提供该信息。

还有其他方法可以做到这一点,但如果你有一个非常长的向量,这将打破循环,所以你不会计算超过你需要的。基本思想是使用 rollapply 创建一个长度为 k 的连续和的向量,然后找到其中的最大值。如果这小于我们想要的,对长度为 k+1 的总和做同样的事情。重复直到我们找到一个大于所需阈值的总和。

编辑:

这似乎快了大约 100 倍。我没有将它与汤米的答案进行比较(这可能比这更快,但与我的原始方法相比,这将提供显着的加速。

编辑 2:移动 [-n] 并删除抑制警告会加快这一速度。

myfun <- function(ev, N){
    i <- 1
    n <- length(ev)
    j <- ev
    repeat{
        j <- (j[-n] + ev[-c(1:i)])
        i <- i+1
        n <- n-1
        if(max(j) >= N | i > length(ev)){
            break;
        }
    }
    return(i)
}

myfun(ev, 20000)

# And stealing the idea from Tommy gives a nice speedup as well
myfuncomp <- compiler:cmpfun(myfun)
myfuncomp(ev, 20000)
myfunc3 <- compiler:cmpfun(myfun, options = list(optimize = 3))
myfunc3(ev, 20000)

library(rbenchmark) # For testing
# If you have Tommy's functions loaded as f and g you can compare
benchmark(f(ev, 20000), g(ev, 20000), myfun(ev, 20000), myfuncomp(ev, 20000), myfunc3(ev, 20000))

【讨论】:

  • 谢谢!这正是我所需要的。不幸的是,它对于大型向量来说非常缓慢。再次感谢。
  • @ECII 我建议接受汤米给出的答案。它好多了,他们提到了编译它,这使它非常快。
  • 我编辑了第二个版本以使其更快。在我的机器上测试它比 Tommy 的稍微快一点,并且使用 optimize = 3 进行编译是我尝试过的所有方法中最好的。
  • @Dason 您的回答给出的初始值与汤米不同。任何想法为什么? : df
  • @ECII 目前没有。这个答案就像8岁。也许我会在星期一回头看。
【解决方案3】:

你的意思是这样的?

> sum(ifelse(cumsum(ev)<=200000, 1, 0))
[1] 364

【讨论】:

  • 没有。让我解释得更好。我想要的是:从 ev[1] 开始并连续添加到 20000。记录您必须添加的元素数量才能达到 20000 作为 r[1]。然后从 ev[2] 开始并添加到 20000 等等。将在 20000 之前必须添加的元素数量记录为 r[2]。在 ev 的整个长度上执行此操作。然后返回 min(r)
【解决方案4】:

我认为这可能是变相的旅行推销员问题,除非您施加更多限制。您不一定要从最大 ev 开始并朝任一方向前进,因为它可能是局部非密集最大值

x=1:length(ev)
 plot(x,ev)
 lxy <- loess(ev~x )
 lines(predict(lxy, x=1:length(y)))
 title(main="loess() fit of ev")

但在值最密集的区域,这些值相当平坦。

 x=1:length(y); y=c(356.83, 
 973.5, 0, 240.43, 1232.07, 1440, 1329.67, 1096.87, 1331.37, 1305.03, 
 1328.03, 1246.03, 1182.3, 1054.53, 723.03, 1171.53, 1263.17, 
 1200.37, 1054.8, 971.4, 936.4, 968.57, 897.93, 1099.87, 876.43, 
 1095.47, 1132, 774.4, 1075.13, 982.57, 947.33, 1096.97, 929.83, 
 1246.9, 1398.2, 1063.83, 1223.73, 1174.37, 1248.5, 1171.63, 1280.57, 
 1183.33, 1016.23, 1082.1, 795.37, 900.83, 1159.2, 992.5, 967.3, 
 1440, 804.13, 418.17, 559.57, 563.87, 562.97, 1113.1, 954.87, 
 883.8, 1207.1, 1046.83, 995.77, 803.93, 1036.63, 946.9, 887.33, 
 727.97, 733.93, 979.2, 1176.8, 1241.3, 1435.6)

 lxyhi <- loess(y~x)
 plot(x,y)
 lines(predict(lxyhi, x=1:length(y)))

【讨论】:

  • 漂亮的图表...但是由于所述问题是找到 连续数字 加起来一个值,我不明白为什么它会是一个 NP 完全问题(就像旅行推销员一样)。
  • 试图定义区域并不容易。如果没有全局搜索,就无法确定应该在哪里扩展区间索引。
  • 我必须承认在这里有点迷失 - 我不是统计学家,但我看待问题的方式(以及我解决问题的方式)是使用(相当)简单的 for 循环.你是说那个算法是错误的?如果是这样,我想了解它失败的情况!
  • 我不认为成为一名统计学家(我也不是)是个问题。我只是说你需要进行全局搜索,但我猜你的需要,而且它比我应用基于密度()的策略的努力要好。 + 给你。
猜你喜欢
  • 2021-04-05
  • 2016-08-19
  • 2017-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多