删除向量中至少N个连续值的序列

时间:2013-12-06 14:56:42

标签: r optimization vector

这是我的问题。我有一个大的正数据向量。我的目标是删除在向量中重复的至少N个连续值的序列(所有重复值必须严格地> 0)。

我写了一个有效的程序,如下: X是我的数值向量; N是重复序列的最小长度。

rmpParNASerieRepetee <- function(X, N)
{
    X_ <- paste("T", paste(X, collapse="T"), "T", sep="")
    ind.parcours <- 1
    ind.sup <- c()

    # Loop on the values
    while ( ind.parcours <= (length(X)-N+1) )
    {
        # indices of my sequence of N values
        deb <- ind.parcours
        fin <- ind.parcours + N-1

        # sequence of N values to search in the vector
        serie  <- X[deb:fin]
        serie_ <- paste("T", paste(serie, collapse="T"), "T", sep="")


        borne <- 1*(ind.parcours < (length(X)-N+1)) + 0*(ind.parcours == (length(X)-N+1))
        if (sum(X[(length(X)-N+1):length(X)]==serie)==3) borne <- 0

        # split my string vector by my sequence vector of N values and count the pieces of result
        if ( length(unlist(strsplit(X_, serie_)))-1 > borne && length(which(serie!=0))>=N)
        { ind.sup <- unique(c(ind.sup, deb:fin)) }
        ind.parcours <- ind.parcours+1
    }
    if (length(ind.sup !=0)) { X[ind.sup] <- NA }

    list_return <- list(X=X, Ind.sup=unique(sort(ind.sup)))
    return (list_return)
}

我认为我的功能真的不是最优的(对于92,000个值的矢量计算时间为1:15,N = 18)。我必须做1600次这个步骤......这需要大约3个月......

有没有人有更好的主意?

示例:

x <- c(1,2,3,4,0,4,1,2,3,8,9,1,2,3,4,0)
N <- 3
# (1,2,3) is a sequence of 3 elements which is repeated
# (1,2,3,4) is  sequence of 4 elements which is repeated
# no other sequence of length at least 3 repeats
# my result should also be :
# NA NA NA NA 0 4 NA NA NA 8 9 NA NA NA NA 0
# The result of my program is :
# $X
# [1] NA NA NA NA  0  4 NA NA NA  8  9 NA NA NA NA  0
#$Ind.sup
# [1]  1  2  3  4  7  8  9 12 13 14 15

4 个答案:

答案 0 :(得分:1)

尝试使用table%in%以提高矢量化速度。

rmpParNASerieRepetee<-function(X,N){
  tab<-table(X[X>0])
  over.n<-as.numeric(names(tab)[tab>=N])
  ind<-X %in% over.n
  Ind.sup<-which(ind)
  X<-ifelse(ind,NA,X)
  list(Ind.sup,X)
}

X <- c(1,2,3,4,0,0,0,0,1,4,1,2,3,4,8,9,1,2,3,1,4,1,0,0,0)
rmpParNASerieRepetee(X,3)
# [[1]]
# [1]  1  2  3  4  9 10 11 12 13 14 17 18 19 20 21 22
# 
# [[2]]
# [1] NA NA NA NA  0  0  0  0 NA NA NA NA NA NA  8  9 NA NA NA NA NA NA  0  0  0

对92000值进行一点测试:

X<-sample(1:10000,92000,TRUE)
system.time(rmpParNASerieRepetee(X,3))
#   user  system elapsed 
#   0.14    0.00    0.14 

答案 1 :(得分:1)

一种方式:

f <- function(X, N)
{
 .rle <- rle(sort(X))
 res <- .rle$values[.rle$lengths >= N]
 res <- res[res > 0]
 inds <- X %in% res
 X[inds] <- NA 
 list(X = X, Ind = which(inds)) 
}

#> f(X, 3)
#$X
# [1] NA NA NA NA  0  0  0  0 NA NA NA NA NA NA  8  9 NA NA NA NA NA NA  0  0  0
#
#$Ind
# [1]  1  2  3  4  9 10 11 12 13 14 17 18 19 20 21 22

答案 2 :(得分:0)

考虑这一点的一种方法是,在一个序列中,每个元素与最后一个元素的区别为1,因此:

X    <- c(1,2,3,4,0,0,0,0,1,4,1,2,3,4,8,9,1,2,3,1,4,1,0,0,0)
y    <- X[-1]
diff <- y-X[1:length(X)-1]
diff
[1]  1  1  1 -4  0  0  0  1  3 -3  1  1  1  4  1 -8  1  1 -2  3 -3 -1  0  0

现在你正在寻找&gt;的序列。 {1}中的N 1。

答案 3 :(得分:0)

我已经优化了我的功能,现在对于长度为92000的向量,“仅”10分钟。 也许有人能找到比我更快的其他解决方案。

想象一下,我的矢量是X<-c(1,2,3,4,0,7,8,1,2,3,NA,8,9,1,2,3,4)N=3c(1,2,3) et c(1,2,3,4)是唯一一个长度至少为N而没有NA或0的重复序列。所以我的结果应该是NA NA NA NA 0 7 8 NA NA NA NA 8 9 NA NA NA NA

为了回答我的问题,我使用了这个原则:

我创建了一个大字符串:X_ <- T1T2T3T4T0T7T8T1T2T3TNAT8T9T1T2T3T4,其中所有X值都由T连接。对于每个长度为N=3的小字符串(例如:第一个是T1T2T3T),我使用X_函数以“小字符串”模式打破我的大字符串strsplit。如果结果的长度大于2,则重复该序列。 必须注意不要在系列中取空值,并且必须进行一些调整以避免边缘现象(在我的函数中borne)......

我创建了这些功能:

# Function to count NA in a vector
count.na <- function(vec) { return (length(which(is.na(vec)))) }

# Function to detect sequence of stricly postive numbers of length at least N
rmpParNASerieRepetee <- function(X, N, val.min=0)
{
    # Collapse the vector to make a big string
    X_ <- paste("T", paste(X, collapse="T"), "T", sep="")

    # Index term
    ind.parcours <- 1
    ind.sup <- c()

    # Loop on X values
    while ( ind.parcours <= (length(X)-N+1) )
    {
         # Selection of the sequence to be detected
         deb <- ind.parcours
         fin <- ind.parcours + N-1
         serie <- X[deb:fin]

            # All values are > 0
            if ( length(which(serie>0)) >= (N-count.na(serie)) )
            {
                    # Research of repetition with strsplit
                    serie_ <- paste("T", paste(serie, collapse="T"), "T", sep="")
                    borne <- 1*(ind.parcours < (length(X)-N+1)) + 0*(ind.parcours == (length(X)-N+1)) 
                    if (sum(X[(length(X)-N+1):length(X)]==serie, na.rm=TRUE)==N) borne <- 0

                    if (length(unlist(strsplit(X_, serie_)))-1 > borne) 
                         ind.sup <- unique( c(ind.sup, deb:fin) )

                    # Incrementation
                    ind.parcours <- ind.parcours + 1
             }
            # Contains 0
            else
            {   ind.parcours <- ind.parcours + max(which(serie==0))
            }
    }

    # Invalidaion of repeated sequences
    if (length(ind.sup !=0)) { X[ind.sup] <- NA }

    # Return
    list_return <- list(X=X, Ind.sup=unique(sort(ind.sup)))
    return (list_return)

 }

我希望有人能找到另一种方法来解决我的问题!