【问题标题】:Efficiently adding or removing elements to a vector or list in R?有效地向 R 中的向量或列表添加或删除元素?
【发布时间】:2011-02-16 05:40:09
【问题描述】:

我正在实现一种算法,该算法涉及大量添加和删除集合中的内容。在 R 中,这很慢,因为据我所知,从向量中添加或删除内容很慢,因为必须重新分配整个向量。有没有更有效的方法?

编辑:我目前的解决方案是使用与集合中可以包含的事物列表长度相同的布尔向量,并将其用作成员表。

【问题讨论】:

  • 您是否有机会提供准确的代码?从您的问题中,我无法确定您使用的是列表还是向量,如何添加或删除(什么功能?)元素,您当前的解决方案如何工作(是重新创建逻辑向量而不是添加/删除到原始?)?您提供的信息越多,可以做的优化就越多。
  • 新版本的 R 应该在这方面做得更好。这是真的吗?
  • 我怀疑在添加或删除元素时反复调整向量的大小会很快。

标签: r vector performance


【解决方案1】:

是的,还有更有效的方法。

这取决于您如何使用数据;你的用例。取出数据的顺序和放入的顺序一样,还是倒序,还是随机,还是排序?

对于FIFO,对于固定大小的数组使用circular buffer,或者对于完全动态的大小,使用deque(发音为deck)。 (这可能是你想要的。)

对于FILO,使用stack

为了随机抓取数据,请考虑使用您从未调整大小的 1 列矩阵。调整大小很慢。

如果您需要有序集(例如c(3,2,5) -> c(2,3,5)),请查看tree or a heap

  • 一棵树适合比较,例如抓取集合中小于 5.5 的所有元素。
  • 堆适合只抓取最大或最小的元素。

【讨论】:

    【解决方案2】:

    The R Inferno 的第 2 章对此有一些有趣的 cmets,包括周期性增长的对象以减少内存碎片和分配开销。

    如果您知道集合的最终大小是多少,那么您建议的方法可能是最好的 - 即使用适当的成员向量来自整个宇宙的subset。很难知道什么是最好的,但没有确切地看到你正在尝试做什么。

    【讨论】:

    • 我最终得到了一个代表集合成员资格的布尔向量。
    【解决方案3】:

    很难说出你想要什么。也许你真的想要像 push 和 pop 这样的堆栈命令。下面不是这样的。但这是一个快速的解决方案。

    分配一个足够大的向量来容纳您需要的所有类型的项目。将每个值设置为 NA。添加项目很简单。删除项目再次将它们设置为 NA。使用向量就是na.omit(myVec)

    myVec <- numeric (maxLength)  # a vector of maximum length
    
    is.na(myVec) <- 1:maxLength   # set every item in myVec to NA
    
    myVec[c(2,6,20)] <- 5         # add some values
    
    na.omit(myVec)
    
    #This will also work if you can initialize all of your values to something that you know you won't need. 
    

    【讨论】:

    • @John: myVec &lt;- rep(NA, maxLength) 更干净地替换了前两行。还有,大写是怎么回事?
    【解决方案4】:

    如果可以,初始化一个向量,使其长度等于算法期间的最大长度可能会有所帮助。

    例如

    vec <- rep(NA,10)
    vec[1:3] <- 1:3
    vec[4:5] <- 4:5
    vec[6:10] <- 6:10
    

    而不是

    vec <- 1:3
    vec <- c(vec,4:5)
    vec <- c(vec,6:10)
    

    比较

    > system.time({vec <- rep(NA,10^4); for (i in 1:(10^4)) vec[i] <- i })
       user  system elapsed 
      0.043   0.001   0.044 
    

    > system.time({vec <- NULL; for (i in 1:(10^4)) vec <- c(vec,i) })
       user  system elapsed 
      0.249   0.089   0.335
    

    【讨论】:

    • 但我可能会删除向量中的任何项目,而不仅仅是最后一个。
    • 当然。这些循环只是说明初始化向量和使用重复赋值构建向量之间的区别的示例。我显然没有看到你的算法,但是这个方法应该仍然有效,因为“i”可以是你算法中任何点的任何数字。它只依赖于知道你的向量的长度。此外,您只需将该元素分配为“NA”并保持相同长度的向量,而不是删除它。
    • 不用eval/parse,用大括号表示就够了,即:system.time({vec &lt;- rep(NA,10^4);for (i in 1:(10^4)) vec[i] &lt;- i})
    • @Marek。很公平。谢谢你。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多