加速R码以计算马尔可夫链中的(高阶)跃迁

加速R码以计算马尔可夫链中的(高阶)跃迁,r,performance,R,Performance,我写了一个小R代码段来遍历一个包含马尔可夫链实现的向量,并返回给定顺序的观察到的转换。 具体来说,假设我们对状态空间$\mathcal{S}$的2阶转换感兴趣。 最终目标是以方便的形式存储计数$n{ijk}$,$i,j,k\in\mathcal{S}$,以供以后使用 get_contingency_array <- function(seq, order){ N <- length(seq) states <- sort(unique(seq)) nstates &

我写了一个小R代码段来遍历一个包含马尔可夫链实现的向量,并返回给定顺序的观察到的转换。 具体来说,假设我们对状态空间$\mathcal{S}$的2阶转换感兴趣。 最终目标是以方便的形式存储计数$n{ijk}$,$i,j,k\in\mathcal{S}$,以供以后使用

get_contingency_array <- function(seq, order){
  N <- length(seq)
  states <- sort(unique(seq))
  nstates <- length(states)
  inds <- seq_along(states)
  K <- order + 1
  out <- array(0, dim = rep(nstates, K))
  for (z in K:N){
    pos <- match(seq[(z - K + 1):z], states)
    s1 <- paste0("out[", paste(pos, collapse = ","), "]")
    s2 <- paste(s1, "<-", s1, "+ 1")
    eval(parse(text = s2))
  }
  return(out)
}

set.seed(666)
X1 <- rbinom(1E5, size = 1, prob = .8)
get_contingency_array(X1, 3)
我的问题是:怎样才能大大加快速度?对于较大的尺寸,它会有一点拖拉。

除了最极端的情况外,在所有情况下都应该避免使用
eval(parse(.)

第一次切割使用一种鲜为人知的方法在带有
矩阵的数组上建立索引。为了演示,我将中断第一个
For
循环的函数调用,并显示修改后数组上的索引:

debug(获取意外事件数组)
获取意外事件数组(X1,3)
###单步执行直到“for”循环,第一次通过:
Z
# [1] 4
###暂时重新分配'out'以显示索引

等等,我非常困惑。为什么
eval
将代码存储为循环中的文本?直接对表达式求值即可。代码更简单,速度也将大大加快。(编辑:啊,明白了。直接看下面的答案。)除了使用
matrix(…,nrow=1)
之外,你还可以使用
t(…)
,它稍微短一点。没错,虽然目标不是编码高尔夫,而是性能,
t(.)
似乎慢了10-15%(不确定为什么)。非常感谢你的帮助。我知道
eval(parse)
会减慢速度,但我不知道如何摆脱它。回答得好@r2evans呃,好吧,这太可怕了(可能是因为
t
是一个泛型)。值得一提的是,我的理由不是代码高尔夫(!?!),而是可读性。
, , 1, 1

     [,1] [,2]
[1,]  148  624
[2,]  613 2567

, , 2, 1

     [,1]  [,2]
[1,]  601  2583
[2,] 2550 10310

, , 1, 2

     [,1]  [,2]
[1,]  613  2527
[2,] 2578 10327

, , 2, 2

      [,1]  [,2]
[1,]  2590 10310
[2,] 10304 40752