【问题标题】:How can I vectorize access to neighbour vector elements in R?如何向量化对 R 中相邻向量元素的访问?
【发布时间】:2013-04-25 15:09:11
【问题描述】:

我有以下向量

 v = c(F, F, F, T, F, F, F, F, F, T, F, F, F)

如何使用矢量化操作更改 v 以便每个 v TRUE 元素的前 2 个元素和后 2 个元素也设置为 TRUE?也就是说,结果应该是:

 F, T, T, T, T, T, F, T, T, T, T, T, F

当然,这可以通过在每个 v 元素上循环来完成,但我想了解是否可以对这种操作进行矢量化。也不同于this question,v 中的元素是独立的,我不需要对每个元素都执行计算。这是一个纯粹的索引问题。

【问题讨论】:

    标签: r


    【解决方案1】:

    这个排序的东西可能和你将要得到的一样矢量化了:

    v[unlist(sapply(which(v),function(x) {x + c(-2,-1,1,2)},simplify = FALSE))] <- TRUE
    > v
     [1] FALSE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE
    

    但请注意,您尚未指定 TRUE 元素在向量末端附近应该发生什么。那将需要更多的工作。如果有两个 TRUE 元素彼此之间的距离小于两个位置,您也没有指定会发生什么。

    或者:

    v[outer(which(v),c(-2,-1,1,2),"+")] <- TRUE
    > v
     [1] FALSE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE
    

    在基本层面上,我们在这里做同样的事情,但第二个选项肯定更紧凑,虽然可能更难理解。

    【讨论】:

    • 您可以修改它以包含这些约束:v[unique(as.vector(sapply(which(v),function(x){if(x&gt;2){x + c(-2,-1,1,2)}else{1:(x+2)}})))] &lt;- TRUE
    • @rmk 是的,尽管我认为这只涉及左侧端点。当然可以为另一端做类似的事情,但我想我们想放弃匿名函数,我想。
    • @rmk 查看此线程以讨论如何在边缘修剪矢量:stackoverflow.com/questions/16220521/how-to-trim-an-r-vector/…
    【解决方案2】:

    聚会迟到...您应该应用卷积过滤器。它会比什么都快。唯一的困难是在两端你应该预先/附加一对FALSE,这样过滤器就不会用NAs 初始化。这是一个可以为您完成的功能:

    within.distance <- function(x, d = 2) {
        xxx  <- c(rep(FALSE, d), x, rep(FALSE, d))
        yyy  <- as.logical(filter(xxx, rep(1, 2*d+1)))
        head(tail(yyy, -d), -d)
    }
    
    within.distance(v)
    #  [1] FALSE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE TRUE FALSE
    

    【讨论】:

    • 证明第一个答案并不总是最好的。不错。
    【解决方案3】:

    这是另一个尝试。它似乎适用于您的数据,并且当第一个元素为 TRUE 时也是如此。

    as.logical(rowSums(embed(c(FALSE, FALSE, v, FALSE, FALSE), 5)))
    #  [1] FALSE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE
    
    # another attempt with beginning and end TRUE
    v = c(T, F, F, F, F, F, T, F, F, F, F, F, T)
    #  [1]  TRUE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE
    

    类似于@flodel 的想法,可以在这里创建一个函数:

    rollOR <- function(vec, dir="both", dist=2) {
        stopifnot(dir %in% c("left", "right", "both"))
        stopifnot(dist >= 0)
        stopifnot(is.logical(vec))
    
        cvec <- rep(FALSE, dist)
        switch(dir, 
            both = {
                vec <- c(cvec, vec, cvec)
                dist <- dist * 2 + 1
            }, 
            left = {
                vec <- c(vec, cvec)
                dist <- dist + 1
            },
            right = {
                vec <- c(cvec, vec)
                dist <- dist + 1
            })
    
        as.logical(rowSums(embed(vec, dist)))
    }   
    # direction both sides
    rollOR(v, "both", 2)
    # [1] FALSE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE
    
    # left alone
    rollOR(v, "left", 2)
    # [1] FALSE  TRUE  TRUE  TRUE FALSE FALSE FALSE  TRUE  TRUE  TRUE FALSE FALSE FALSE
    
    # right alone
    rollOR(v, "right", 2)
    # [1] FALSE FALSE FALSE  TRUE  TRUE  TRUE FALSE FALSE FALSE  TRUE  TRUE  TRUE FALSE
    

    【讨论】:

      【解决方案4】:

      另一种方法。创建一组滞后向量,并将它们 or 在一起:

      library(Hmisc)
      library(functional)
      within.distance <- function(x, d=2) {
        FLag <- function(x, shift) {
          x <- Lag(x, shift)
          x[is.na(x)] <- FALSE
          return(x)
        }
      
        l <- lapply((-d):d, Curry(FLag, x=x))
        return(Reduce(`|`, l))
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-12-28
        • 1970-01-01
        • 1970-01-01
        • 2018-12-16
        • 2014-03-05
        • 1970-01-01
        • 2014-06-06
        • 1970-01-01
        相关资源
        最近更新 更多