计算子系列的长度

时间:2016-12-12 14:26:35

标签: r

想象一下像

这样的一系列数字
c(21,22,23,30,31,32,34,35,36,37,38,50,NA,52)

子系列定义为:x[t]x[t] = x[t-1] + 1的某个子系列的一部分吗?

所以在上面的例子中我们有以下系列:

c(21,22,23,30,31,32,34,35,36,37,38,50,NA,52)
## 1  1  1  2  2  2  3  3  3  3  3  4  -  5    # serie ID
##    3    |   3    |      5      | 1 | | 1    # length

标记子系列并计算其长度的最有效方法是什么(作为单个函数或两个单独的函数)?

2 个答案:

答案 0 :(得分:3)

我们可以得到相邻元素之间的差异,检查它是否等于1,得到累积和,并将其用作组来获得向量的长度

unname(tapply(v1, cumsum(c(TRUE, diff(replace(v1, is.na(v1), 0))!=1)), length))
#[1] 3 3 5 1 1 1

如果我们需要NA元素作为""

unname(tapply(v1, cumsum(c(TRUE, diff(replace(v1, is.na(v1), 0))!=1)), 
            function(x) if(all(is.na(x))) "" else length(x)))
#[1] "3" "3" "5" "1" ""  "1"

@DavidArenburg与rle

发布的变体
rle(cumsum(c(TRUE, diff(replace(v1, is.na(v1), 0))!=1)))$lengths

答案 1 :(得分:1)

我接受 akrun 的回答(由 David Arenburg 提供),但为了参考,我提供了一个 Rcpp 解决方案我在此期间创造。

NumericVector cpp_seriesLengths(NumericVector x) {
  int n = x.length();
  if (n == 1)
    return wrap(1);
  NumericVector out(n);
  int tmpCount = 1;
  int prevStart = 0;

  for (int i = 0; i < (n-1); i++) {
    if ( x[i] == (x[i+1] - 1) ) {
      tmpCount += 1;
    } else {
      for (int j = prevStart; j <= i; j++)
        out[j] = tmpCount;
      tmpCount = 1;
      prevStart = i+1;
    }
  }
  for (int j = prevStart; j < n; j++)
    out[j] = tmpCount;

  return out;
}