Performance 求R中矩阵中整数向量索引的最快方法

Performance 求R中矩阵中整数向量索引的最快方法,performance,r,vector,comparison,integer,Performance,R,Vector,Comparison,Integer,在R中有以下问题(对于马尔可夫链)。假设有一个状态空间矩阵S,其中有行唯一的整数向量(状态)。我从这个矩阵中得到了一个向量s,我想确定对应于这个向量的行的索引。有两种解决方案: 使用all.equal的解决方案,如: which(apply(S,1,function(x){ isTRUE(all.equal(s,x)) }) ) 将向量映射到唯一字符串,并使用此字符串标识它们: statecodes <- apply(S,1,function(x) paste(x,collapse="

在R中有以下问题(对于马尔可夫链)。假设有一个状态空间矩阵S,其中有行唯一的整数向量(状态)。我从这个矩阵中得到了一个向量s,我想确定对应于这个向量的行的索引。有两种解决方案:

  • 使用
    all.equal
    的解决方案,如:

    which(apply(S,1,function(x){ isTRUE(all.equal(s,x)) }) )
    
  • 将向量映射到唯一字符串,并使用此字符串标识它们:

    statecodes <- apply(S,1,function(x) paste(x,collapse=" ") ) 
    check.equal <- function(s) {
        z <- which(statecodes == paste(s, collapse=" "))
        return(z)
    }
    check.equal(s)
    

    statecodes一种方法是
    其中(colSums(abs(t(S)-V))==0)
    其中
    V
    是您要查找的向量。

    获取每个状态的整数值的一种简单方法是将值转换为整数,然后将每列乘以右基

    我的版本是
    makecheck2
    ;使用粘贴的版本是
    makecheck2
    。我还修改了
    粘贴
    版本以使用
    匹配
    ,因此它可以同时检查多个值。现在,两个版本都返回一个用于获取匹配项的函数

    我的版本设置更快;0.065秒对1.552秒

    N <- 5
    I <- rep(10,N)
    S <- as.matrix(expand.grid( lapply(1:N, function(i) { 0:I[i]}) ) )
    system.time(f1 <- makecheck1(S))
    #   user  system elapsed 
    #  1.547   0.000   1.552 
    system.time(f2 <- makecheck2(S))
    #   user  system elapsed 
    #  0.063   0.000   0.065 
    
    两个版本的代码如下所示:

    makecheck2 <- function(m) {
      codes <- vector("list", length=ncol(m))
      top <- vector("integer", length=ncol(m)+1)
      top[1L] <- 1L
      for(idx in 1:ncol(m)) {
        codes[[idx]] <- unique(m[,idx])
        top[idx+1L] <- top[idx]*length(codes[[idx]])
      }
      getcode <- function(x) {
        out <- 0L
        for(idx in 1:length(codes)) {
          out <- out + top[idx]*match(x[,idx], codes[[idx]])
        }
        out
      }
      key <- getcode(m)
      f <- function(x) {
        if(!is.matrix(x)) {
          x <- matrix(x, ncol=length(codes))
        }
        match(getcode(x), key)
      }
      rm(m) # perhaps there's a better way to remove these from the closure???
      rm(idx)
      f
    }
    
    makecheck1 <- function(m) {
      n <- ncol(m)
      statecodes <- apply(m,1,function(x) paste(x,collapse=" ") )
      rm(m)
      function(x) {
        if(!is.matrix(x)) {
          x <- matrix(x, ncol=n)
        }
        x <- apply(x, 1, paste, collapse=" ")
        match(x, statecodes)
      }
    }
    

    makecheck2不应将
    V
    替换为
    矩阵(V,nrow,ncol,byrow=TRUE)
    ?谢谢提示。这是可行的,但似乎比将向量映射到唯一标识符(我的第二种方法)要慢。我想更多的是把一个向量转换成一个唯一的整数,但还不知道如何转换。这个比较需要反复进行,所以应该非常快,最好不要太占用内存。哇。您的解决方案大约快六倍。我想知道是否可以做得更快。对572392x6矩阵重复这两个步骤1000次。你的91.61秒,我的10.35秒。在这么大的矩阵上做所有的向量运算也会占用更多的内存。虽然我有一些想法,但这要求输出是数值而不是字符串。换句话说:我需要一个更好的映射。除非我遗漏了什么,否则,
    sum(abs(X-Y))==0
    是必要的,但还不够。它本质上是一个弱校验和。如果希望X的每个元素都等于Y中对应的元素,则需要检查每个元素对。另一种方法是使用等效的FEC(前向纠错)编码方法来实现高概率的完全模式匹配。在第二种解决方案中,创建状态码所需的时间是否重要?也就是说,如果要对每个状态空间进行大量测试,那么这一部分只需执行一次,因此速度可能会较慢。但是,如果您只对每个状态空间执行一个测试,那么无论如何都需要对每个测试执行该测试。首选的解决方案可能会有所不同,这取决于您所处的条件。我会对状态空间矩阵中的每个向量重复执行这些比较,多次。因此,状态码向量的创建时间不是很重要。我先牺牲一点时间,以便以后生活得更好。也许我应该提一下。因此,我正在寻找一种可以使搜索尽可能快的方法,而不考虑预计算的时间。如果您的值是(小的)整数,并且可以很容易地使其变为非负,那么这可以加快速度,因为
    匹配
    与唯一值匹配是不必要的。(如果可能需要小量以避免溢出)PPS。还有,请检查我的数学。我有一种预感,我应该先将匹配结果减去1,然后再乘以基数。另外,我认为这基本上就是@danas的评论中的链接。zuokas的答案就是这样做的。非常有用!我明天会更仔细地看一看,但这似乎正是我要找的东西。是的,这很好用!顺便说一句,对于单次比较,
    哪个
    匹配
    快,但是对于多次比较,
    匹配
    更快。为了进行多重比较,我必须重写我的代码。非常感谢你的帮助!
    > set.seed(5)
    > k <- lapply(0:4, function(idx) sample(1:nrow(S), 10^idx))
    > s <- lapply(k, function(idx) S[idx,])
    > t1 <- sapply(s, function(x) unname(system.time(for(i in 1:100) f1(x))[1]))
    > t2 <- sapply(s, function(x) unname(system.time(for(i in 1:100) f2(x))[1]))
    > data.frame(n=10^(0:4), time1=t1, time2=t2)
          n time1 time2
    1     1 0.761 1.512
    2    10 0.772 1.523
    3   100 0.857 1.552
    4  1000 1.592 1.547
    5 10000 9.651 1.848
    
    makecheck2 <- function(m) {
      codes <- vector("list", length=ncol(m))
      top <- vector("integer", length=ncol(m)+1)
      top[1L] <- 1L
      for(idx in 1:ncol(m)) {
        codes[[idx]] <- unique(m[,idx])
        top[idx+1L] <- top[idx]*length(codes[[idx]])
      }
      getcode <- function(x) {
        out <- 0L
        for(idx in 1:length(codes)) {
          out <- out + top[idx]*match(x[,idx], codes[[idx]])
        }
        out
      }
      key <- getcode(m)
      f <- function(x) {
        if(!is.matrix(x)) {
          x <- matrix(x, ncol=length(codes))
        }
        match(getcode(x), key)
      }
      rm(m) # perhaps there's a better way to remove these from the closure???
      rm(idx)
      f
    }
    
    makecheck1 <- function(m) {
      n <- ncol(m)
      statecodes <- apply(m,1,function(x) paste(x,collapse=" ") )
      rm(m)
      function(x) {
        if(!is.matrix(x)) {
          x <- matrix(x, ncol=n)
        }
        x <- apply(x, 1, paste, collapse=" ")
        match(x, statecodes)
      }
    }