比较相同向量的相邻元素(避免循环)

时间:2011-08-05 11:14:14

标签: r vector string-comparison sapply

我设法写了一个for loop来比较以下向量中的字母:

bases <- c("G","C","A","T")
test <- sample(bases, replace=T, 20)

test将返回

[1] "T" "G" "T" "G" "C" "A" "A" "G" "A" "C" "A" "T" "T" "T" "T" "C" "A" "G" "G" "C"

使用函数Comp()我可以检查字母是否与下一个字母匹配

Comp <- function(data)
{
    output <- vector()
    for(i in 1:(length(data)-1))
    {
    if(data[i]==data[i+1])
        {
        output[i] <-1
        }
        else
        {
        output[i] <-0
        }
    }
    return(output)
}

导致;

> Comp(test)
 [1] 0 0 0 0 0 1 0 0 0 0 0 1 1 1 0 0 0 1 0

这是有效的,但是它的数量很大。因此我尝试了sapply()

Comp <- function(x,i) if(x[i]==x[i+1]) 1 else 0
unlist(lapply(test, Comp, test))

不幸的是它无效...(Error in i + 1 : non-numeric argument to binary operator)我无法弄清楚如何访问向量中的前一个字母来进行比较。另外length(data)-1,“不比较”最后一个字母可能会成为一个问题。

谢谢大家的帮助!

干杯 幸运

3 个答案:

答案 0 :(得分:13)

只是“滞后”test并使用==,它是矢量化的。

bases <- c("G","C","A","T")
set.seed(21)
test <- sample(bases, replace=TRUE, 20)
lag.test <- c(tail(test,-1),NA)
#lag.test <- c(NA,head(test,-1))
test == lag.test

更新

此外,您的Comp功能很慢,因为初始化时未指定output的长度。我怀疑你试图预先分配,但是vector()创建了一个零长度向量,必须在循环的每次迭代期间扩展。如果您将通话更改为Compvector(),则vector(length=NROW(data)-1)功能会明显加快。

set.seed(21)
test <- sample(bases, replace=T, 1e5)
system.time(orig <- Comp(test))
#    user  system elapsed 
#  34.760   0.010  34.884 
system.time(prealloc <- Comp.prealloc(test))
#    user  system elapsed 
#    1.18    0.00    1.19 
identical(orig, prealloc)
# [1] TRUE

答案 1 :(得分:3)

@Joshua写道,你当然应该使用矢量化 - 它更有效率。 ...但仅供参考,您的Comp功能仍然可以稍微优化一下。

比较的结果是TRUE/FALSE,它是1/0的美化版本。此外,确保结果是整数而不是数字消耗一半的内存。

Comp.opt <- function(data)
{
    output <- integer(length(data)-1L)
    for(i in seq_along(output))
    {
        output[[i]] <- (data[[i]]==data[[i+1L]])
    }
    return(output)
}

......和速度差:

> system.time(orig <- Comp(test))
   user  system elapsed 
  21.10    0.00   21.11 
> system.time(prealloc <- Comp.prealloc(test))
   user  system elapsed 
   0.49    0.00    0.49 
> system.time(opt <- Comp.opt(test))
   user  system elapsed 
   0.41    0.00    0.40 
> all.equal(opt, orig) # opt is integer, orig is double
[1] TRUE

答案 2 :(得分:0)

看看这个:

> x = c("T", "G", "T", "G", "G","T","T","T")
> 
> res = sequence(rle(x)$lengths)-1
> 
> dt = data.frame(x,res)
> 
> dt
  x res
1 T   0
2 G   0
3 T   0
4 G   0
5 G   1
6 T   0
7 T   1
8 T   2

可能会更快地完成工作。