【问题标题】:Check whether vector in R is sequential?检查R中的向量是否是顺序的?
【发布时间】:2011-12-14 15:13:02
【问题描述】:

我如何检查一个整数向量是否是“连续的”,即后续元素之间的差异是否正好是一个。我觉得我缺少像“is.sequential”这样的东西

这是我自己的函数:

is.sequential <- function(x){
    all(diff(x) == rep(1,length(x)-1))
}    

【问题讨论】:

  • 所以 2:5 被认为是一个序列,但 5:2 不是?
  • ...c(1.5, 2.5, 3.5) 和带有舍入错误的序列呢?
  • @Tommy。好点。在我的情况下,只有整数是相关的,没有小数。目前我还没有过多考虑倒序,但我承认这也可能很有趣。

标签: r sequence


【解决方案1】:

不需要rep,因为 1 将被回收:

编辑以允许 5:2 为真

is.sequential <- function(x){
  all(abs(diff(x)) == 1)
}  

允许不同的序列

is.sequential <- function(x){
 all(diff(x) == diff(x)[1])
}

【讨论】:

  • @CarlWitthoft :注意“all.equal”与stackoverflow.com/a/7667703/662787 :-)
  • @Tommy:因为我也在那里评论过,我想你只是让我们陷入了无限循环~_*
  • 而且,虽然这可能是需要的,但应注意,使用此定义 is.sequential(c(1, 2, 1, 2)) -&gt; T
  • @shujaa 这只发生在第一个定义中
【解决方案2】:

所以,@Iselzer 有一个很好的答案。但是仍然存在一些极端情况:舍入误差和起始值。这是一个允许舍入错误但检查第一个值(几乎)是整数的版本。

is.sequential <- function(x, eps=1e-8) {
  if (length(x) && isTRUE(abs(x[1] - floor(x[1])) < eps)) {
     all(abs(diff(x)-1) < eps)
  } else {
    FALSE
  }
}

is.sequential(2:5) # TRUE

is.sequential(5:2) # FALSE

# Handle rounding errors?
x <- ((1:10)^0.5)^2
is.sequential(x) # TRUE

# Does the sequence need to start on an integer?
x <- c(1.5, 2.5, 3.5, 4.5)
is.sequential(x) # FALSE

# Is an empty vector a sequence?
is.sequential(numeric(0)) # FALSE

# What about NAs?
is.sequential(c(NA, 1)) # FALSE

【讨论】:

    【解决方案3】:

    这个问题现在已经很老了,但在某些情况下,知道向量是否是连续的实际上非常有用。

    两个 OP 答案都很好,但正如 Tommy 所说,公认的答案有一些缺陷。 “序列”是任何“等距的数字序列”,这似乎很自然。这将包括负序列、起始值不是 0 或 1 的序列,等等。

    下面给出了一个非常多样化且安全的实现,它解释了

    1. 负值(-3 到 1)和负方向(3 到 1)
    2. 没有整数步长的序列(3.5、3.6、3.7...)
    3. 错误的输入类型,例如无限值、NA 和 NAN 值、data.frames 等。
    is.sequence <- function(x, ...)
        UseMethod("is.sequence", x)
    is.sequence.default <- function(x, ...){
        FALSE
    }
    is.sequence.numeric <- function(x, tol = sqrt(.Machine$double.eps), ...){
        if(anyNA(x) || any(is.infinite(x)) || length(x) <= 1 || diff(x[1:2]) == 0)
            return(FALSE)
        diff(range(diff(x))) <= tol
    }
    is.sequence.integer <- function(x, ...){
        is.sequence.numeric(x, ...)
    }
    n <- 1236
    #Test:
    is.sequence(seq(-3, 5, length.out = n))
    # TRUE
    is.sequence(seq(5, -3, length.out = n))
    # TRUE
    is.sequence(seq(3.5, 2.5 + n, length.out = n))
    # TRUE
    is.sequence(LETTERS[1:7])
    

    基本上,实现会检查差异的最大值和最小值是否完全相等。

    虽然使用 S3 类方法会使实现稍微复杂一些,但它简化了对错误输入类型的检查,并允许实现其他类。例如,这使得将这个方法扩展为 Date 对象变得很简单,这需要考虑是否只有工作日(或工作日)的序列也是一个序列。

    速度对比

    此实现非常安全,但使用 S4 类会增加一些开销。对于小长度向量,好处是实现的多样性,而在最坏的情况下它会慢 15% 左右。然而,对于较大的向量,它会稍微快一些,如下面的微基准所示。

    请注意,中间时间更适合比较,因为垃圾清理器可能会在基准测试中添加不确定的时间。

    ss <- seq(1, 1e6)
    microbenchmark::microbenchmark(is.sequential(ss),
                                   is.sequence(ss), #Integer calls numeric, adding a bit of overhead
                                   is.sequence.numeric(ss))
    # Unit: milliseconds
    # expr                         min       lq     mean   median       uq      max neval
    # is.sequential(ss)       19.47332 20.02534 21.58227 20.45541 21.23700 66.07200   100
    # is.sequence(ss)         16.09662 16.65412 20.52511 17.05360 18.23958 61.23029   100
    # is.sequence.numeric(ss) 16.00751 16.72907 19.08717 17.01962 17.66150 55.90792   100 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-04-24
      • 2015-12-14
      • 2011-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多