30

假设我的向量数包含 c(1,2,3,5,7,8),我希望找出它是否包含 3 个连续的数字,在这种情况下是 1,2,3。

numbers = c(1,2,3,5,7,8)
difference = diff(numbers) //The difference output would be 1,1,2,2,1

为了验证我的数字向量中是否有 3 个连续整数,我尝试了以下方法,但几乎没有回报。

rep(1,2)%in%difference 

上面的代码在这种情况下有效,但如果我的差异向量 = (1,2,2,2,1),即使“1”不连续,它仍然会返回 TRUE。

4

5 回答 5

25

使用diffand rle,这样的事情应该可以工作:

result <- rle(diff(numbers))
any(result$lengths>=2 & result$values==1)
# [1] TRUE

针对下面的评论,我之前的回答是专门只测试length==3不包括较长长度的运行。更改==>=解决此问题。它也适用于涉及负数的运行:

> numbers4 <- c(-2, -1, 0, 5, 7, 8)
> result <- rle(diff(numbers4))
> any(result$lengths>=2 & result$values==1)
[1] TRUE
于 2013-04-20T08:02:42.590 回答
15

基准!

我包括我的几个功能。随意添加你的。要符合条件,您需要编写一个通用函数来判断向量是否x包含n或更多连续数字。我在下面提供了一个单元测试功能。


竞争者:

flodel.filter <- function(x, n, incr = 1L) {
  if (n > length(x)) return(FALSE)
  x <- as.integer(x)
  is.cons <- tail(x, -1L) == head(x, -1L) + incr
  any(filter(is.cons, rep(1L, n-1L), sides = 1, method = "convolution") == n-1L,
      na.rm = TRUE)
}

flodel.which <- function(x, n, incr = 1L) {
  is.cons <- tail(x, -1L) == head(x, -1L) + incr
  any(diff(c(0L, which(!is.cons), length(x))) >= n)
}

thelatemail.rle <- function(x, n, incr = 1L) {
  result <- rle(diff(x))
  any(result$lengths >= n-1L  & result$values == incr)
}

improved.rle <- function(x, n, incr = 1L) {
  result <- rle(diff(as.integer(x)) == incr)
  any(result$lengths >= n-1L  & result$values)
}

carl.seqle <- function(x, n, incr = 1) {
  if(!is.numeric(x)) x <- as.numeric(x) 
  z <- length(x)  
  y <- x[-1L] != x[-z] + incr 
  i <- c(which(y | is.na(y)), z) 
  any(diff(c(0L, i)) >= n)
}

单元测试:

check.fun <- function(fun)
  stopifnot(
    fun(c(1,2,3),   3),
   !fun(c(1,2),     3),
   !fun(c(1),       3),
   !fun(c(1,1,1,1), 3),
   !fun(c(1,1,2,2), 3),
    fun(c(1,1,2,3), 3)
  )

check.fun(flodel.filter)
check.fun(flodel.which)
check.fun(thelatemail.rle)
check.fun(improved.rle)
check.fun(carl.seqle)

基准:

x <- sample(1:10, 1000000, replace = TRUE)

library(microbenchmark)
microbenchmark(
  flodel.filter(x, 6),
  flodel.which(x, 6),
  thelatemail.rle(x, 6),
  improved.rle(x, 6),
  carl.seqle(x, 6),
  times = 10)

# Unit: milliseconds
#                   expr       min       lq   median       uq      max neval
#    flodel.filter(x, 6)  96.03966 102.1383 144.9404 160.9698 177.7937    10
#     flodel.which(x, 6) 131.69193 137.7081 140.5211 185.3061 189.1644    10
#  thelatemail.rle(x, 6) 347.79586 353.1015 361.5744 378.3878 469.5869    10
#     improved.rle(x, 6) 199.35402 200.7455 205.2737 246.9670 252.4958    10
#       carl.seqle(x, 6) 213.72756 240.6023 245.2652 254.1725 259.2275    10
于 2013-04-20T12:37:43.780 回答
10

diff您可以检查any连续1的 s 之后 -

numbers = c(1,2,3,5,7,8)

difference = diff(numbers) == 1
## [1]  TRUE  TRUE FALSE FALSE  TRUE

## find alteast one consecutive TRUE
any(tail(difference, -1) &
    head(difference, -1))

## [1] TRUE
于 2013-04-20T08:02:36.490 回答
7

很高兴在这里看到本土解决方案。

Stack Overflow 用户Carl Witthoft发布了一个他命名的函数并在此seqle()分享。

该函数如下所示:

seqle <- function(x,incr=1) { 
  if(!is.numeric(x)) x <- as.numeric(x) 
  n <- length(x)  
  y <- x[-1L] != x[-n] + incr 
  i <- c(which(y|is.na(y)),n) 
  list(lengths = diff(c(0L,i)),
       values = x[head(c(0L,i)+1L,-1L)]) 
} 

让我们看看它的实际效果。首先,一些数据:

numbers1 <- c(1, 2, 3, 5, 7, 8)
numbers2 <- c(-2, 2, 3, 5, 6, 7, 8)
numbers3 <- c(1, 2, 2, 2, 1, 2, 3)

现在,输出:

seqle(numbers1)
# $lengths
# [1] 3 1 2
# 
# $values
# [1] 1 5 7
# 
seqle(numbers2)
# $lengths
# [1] 1 2 4
# 
# $values
# [1] -2  2  5
# 
seqle(numbers3)
# $lengths
# [1] 2 1 1 3
# 
# $values
# [1] 1 2 2 1
# 

您特别感兴趣的是结果中的“长度”。

另一个有趣的观点是incr争论。在这里,我们可以将增量设置为“2”,并查找数字之间的差为 2 的序列。因此,对于第一个向量,我们希望检测到 3、5 和 7 的序列。

我们试试看:

> seqle(numbers1, incr = 2)
$lengths
[1] 1 1 3 1

$values
[1] 1 2 3 8

因此,如果我们设置 ,我们可以看到我们有 1 (1)、1 (2)、3 (3, 5, 7) 和 1 (8) 的序列incr = 2


它如何与 ECII 的第二个挑战一起工作?好像没问题!

> numbers4 <- c(-2, -1, 0, 5, 7, 8)
> seqle(numbers4)
$lengths
[1] 3 1 2

$values
[1] -2  5  7
于 2013-04-20T08:33:24.767 回答
5

简单但有效

numbers = c(-2,2,3,4,5,10,6,7,8)
x1<-c(diff(numbers),0)
x2<-c(0,diff(numbers[-1]),0)
x3<-c(0,diff(numbers[c(-1,-2)]),0,0)

rbind(x1,x2,x3)
colSums(rbind(x1,x2,x3) )==3 #Returns TRUE or FALSE where in the vector the consecutive intervals triplet takes place
[1] FALSE  TRUE  TRUE FALSE FALSE FALSE  TRUE FALSE FALSE

sum(colSums(rbind(x1,x2,x3) )==3) #How many triplets of consecutive intervals occur in the vector
[1] 3

which(colSums(rbind(x1,x2,x3) )==3) #Returns the location of the triplets consecutive integers
[1] 2 3 7

请注意,这对于连续的负间隔不起作用,c(-2,-1,0)因为它是如何diff()工作的

于 2013-04-20T08:31:53.883 回答