сравнить соседние элементы одного и того же вектора (избегая петель) - PullRequest
5 голосов
/ 05 августа 2011

Мне удалось написать 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 ]

13 голосов
/ 05 августа 2011

Просто "лаг" 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() создает вектор нулевой длины, который должен быть расширен во время каждой итерации вашего цикла. Ваша Comp функция значительно быстрее, если вы измените вызов на vector() на 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
3 голосов
/ 05 августа 2011

Как писал @ Джошуа, вы, конечно, должны использовать векторизацию - это намного эффективнее.... Но просто для справки, ваша функция 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
1 голос
/ 07 августа 2015

Посмотрите на это:

> 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

Может работать быстрее.

...