2015-06-20 55 views
3

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

  1. 如果有一个由真值包围的FALSE,请将其切换为TRUE。
  2. 如果少于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语句。

有没有更好的方式来得到这个工作?

+0

这是一个普遍的问题,似乎在r-SO上出现了很多 - 在向量化/矩阵中应用矢量化而不是循环方式的操作,其中应用于一个元素的函数依赖于其他由索引标识的元素,所以它不仅仅是应用系列函数的简单使用。我不够R的忍者写关于如何自己做这个教程的教程,但有人oughta ... –

回答

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 

接着,寻找TRUE(和FALSE)的那些长度小于3运行,并且它们设置为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 
+0

谢谢!这是一个非常漂亮的解决方案。完美的作品。我将不得不学习很多! – Stefan

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 
+0

@plafort信誉去弗兰克修改它。我喜欢你的'正则表达式' – akrun

+0

@plafort这不是在这里。我试图用sql命令替换列中的一些值。不正确。我会试着弄明白。谢谢。 – akrun

+0

我很难拉我的正则表达式匹配的第一个实例。它似乎深深地陷入了'gregexpr'输出中,并带有一系列属性。你知道更快的方法吗? –

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

+0

也是一个非常好的方法。非常感谢! – Stefan