首页 文章

替换/修改逻辑矢量中的值(模式匹配)

提问于
浏览
3

这个问题看起来很简单,但我没弄清楚它是如何在R中完成的 . 我想根据其值的模式修改逻辑向量 . 有两个修改步骤:

  • 如果有一个被TRUE值包围的FALSE,请将其切换为TRUE .

  • 如果有少于3个连续的TRUE值,则将它们切换为FALSE .

其他一切都应该保持不变 . 这是一个例子:

# input  
x = c(FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE,
    FALSE, TRUE, TRUE, FALSE, FALSE, TRUE,  TRUE,  TRUE,  TRUE, FALSE)

# output
xo = c(FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, 
   TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE,  TRUE,  TRUE,  TRUE, FALSE)

cbind(x,xo)

x    xo
 [1,] FALSE FALSE
 [2,]  TRUE FALSE
 [3,] FALSE FALSE
 [4,] FALSE FALSE
 [5,]  TRUE FALSE
 [6,]  TRUE FALSE
 [7,] FALSE FALSE
 [8,] FALSE FALSE
 [9,]  TRUE  TRUE
[10,]  TRUE  TRUE
[11,]  TRUE  TRUE
[12,] FALSE  TRUE
[13,]  TRUE  TRUE
[14,]  TRUE  TRUE
[15,] FALSE FALSE
[16,] FALSE FALSE
[17,]  TRUE  TRUE
[18,]  TRUE  TRUE
[19,]  TRUE  TRUE
[20,]  TRUE  TRUE
[21,] FALSE FALSE

我不想使用for循环,因为它很慢,我将不得不做很多if语句 .

有没有更好的方法让这个工作?

3 回答

  • 3

    这是一种方法:

    #sample data 
    x <- c(FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE,
        FALSE, TRUE, TRUE, FALSE, FALSE, TRUE,  TRUE,  TRUE,  TRUE, FALSE)
    

    首先,找到FALSE值需要更改为TRUE值的索引,方法是查找后面的FALSE值,后面跟着TRUE值

    tochange <- 
      intersect(
        intersect(
         which(x == FALSE),   # not strictly necessary
         which(diff(x) == 1)  # FALSEs followed by a TRUE
         ),
        which(diff(x) == -1) + 1 # FALSEs that follow a TRUE
        )
    

    更改值

    x[tochange] <- TRUE
    

    接下来,查找长度小于3的TRUE(和FALSE)运行,并将它们设置为FALSE .

    xrle <- rle(x)
    
    xrle$values[xrle$lengths < 3] <-  FALSE
    
    newx <- inverse.rle(xrle) # thanks to Frank for pointing out inverse.rle!
    
    # [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE
    #[10]  TRUE  TRUE  TRUE  TRUE  TRUE FALSE FALSE  TRUE  TRUE
    #[19]  TRUE  TRUE FALSE
    
  • 1

    您可以尝试 rle (感谢@Frank进行修改)

    xtmp <- inverse.rle(within.list(rle(x),{
        n    <- length(values)
        values[lengths == 1 & !values & ! seq_len(n) %in% c(1,n)] <- TRUE
    }))
    
    res <- inverse.rle(within.list(rle(xtmp),
        values[lengths < 3 & values] <- FALSE
    ))
    
    identical(xo,res) # TRUE
    
  • 3

    尝试:

    make_true <- function(x) {
      string <- paste(as.numeric(x), collapse='')
      ans <- gregexpr('(?=(101))', string, perl=T)
      x[as.numeric(ans[[1]])+1L] <- TRUE
      res <- rle(x)
      res$values[res$lengths < 3] <- FALSE
      inverse.rle(res)
    }
    

    该函数利用了T和F可以被强制转换为数字的事实 . 搜索的模式是“101” .

相关问题