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

时间:2015-06-20 15:16:50

标签: r

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

  1. 如果有一个被TRUE值包围的FALSE,请将其切换为TRUE。
  2. 如果有少于3个连续的TRUE值,请将它们切换为FALSE。
  3. 其他一切都应保持原样。这是一个例子:

    # 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 个答案:

答案 0 :(得分:3)

您可以尝试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

答案 1 :(得分: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

答案 2 :(得分:1)

尝试:

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”。