在R中找到连续的零序列

Man*_*ino 12 r data.table

我有一个data.frame真的很大(实际上是一个data.table).现在,为简化起见,我们假设我的data.frame如下:

x <- c(1, 1, 0, 0, 1, 0, 0, NA, NA, 0) 
y <- c(1 ,0 ,NA, NA, 0, 0, 0, 1, 1, 0)
mydf <- data.frame(rbind(x,y))
Run Code Online (Sandbox Code Playgroud)

我想确定哪一行(如果有的话)最后一个序列由三个连续的零形成,而不是考虑NA.因此,在上面的示例中,第一行在最后一个序列中有三个连续的零,但不是第二个.

如果我只有一个向量(不是data.frame),我知道如何做到这一点:

runs <-  rle(x[is.na(x)==F])

runs$lengths[length(runs$lengths)] > 2 & runs$values[length(runs$lengths)]==0
Run Code Online (Sandbox Code Playgroud)

我显然可以做一个循环,我会得到我想要的东西.但它的效率非常低,我的实际数据框架非常大.那么,关于如何以最快的方式做的任何想法?

我猜申请可能很有用,但我现在无法考虑使用它.此外,也许有一种data.table方式这样做?

ps.:实际上,这个data.frame是我原始data.table的重新整形版本.如果以某种方式我可以使用原始格式的data.frame完成工作,那没关系.要了解我的data.frame原来是什么,只需将其视为:

x <- c(1, 1, 0, 0, 1, 0, 0, 0) 
y <- c(1 ,0 , 0, 0, 0, 1, 1, 0)

myOriginalDf <- data.frame(value=c(x,y), id=rep(c('x','y'), c(length(x), length(y))))
Run Code Online (Sandbox Code Playgroud)

mne*_*nel 20

使用data.table,正如你的问题建议你真正想要的,就我所知,这就是做你想要的

DT <- data.table(myOriginalDf)

# add the original order, so you can't lose it
DT[, orig := .I]

# rle by id, saving the length as a new variables

DT[, rleLength := {rr <- rle(value); rep(rr$length, rr$length)}, by = 'id']

# key by value and length to subset 

setkey(DT, value, rleLength)

# which rows are value = 0 and length > 2

DT[list(0, unique(rleLength[rleLength>2])),nomatch=0]

##    value rleLength id orig
## 1:     0         3  x    6
## 2:     0         3  x    7
## 3:     0         3  x    8
## 4:     0         4  y   10
## 5:     0         4  y   11
## 6:     0         4  y   12
## 7:     0         4  y   13
Run Code Online (Sandbox Code Playgroud)


Mar*_*ler 8

这是一个基于您的矢量解决方案的apply语句.它可能会做你想要的.

z <- apply(mydf,1, function(x) {
runs <-  rle(x[is.na(x)==FALSE]) ;
runs$lengths[length(runs$lengths)] > 2 & runs$values[length(runs$lengths)]==0 })

mydf[z,]

#   X1 X2 X3 X4 X5 X6 X7 X8 X9 X10
# x  1  1  0  0  1  0  0 NA NA   0
Run Code Online (Sandbox Code Playgroud)


Ric*_*rta 6

isMidPoint0如果有中间,下面将标识中间.

library(data.table)
myOriginalDf <- data.table(myOriginalDf, key="id")

myOriginalDf[, isMidPoint := FALSE]
myOriginalDf <- myOriginalDf[!is.na(value)][(c(FALSE, !value[-(1:2)], FALSE) & c(!value[-(length(value))], FALSE) & c(FALSE, !value[-length(value)])), isMidPoint := TRUE, by=id]
Run Code Online (Sandbox Code Playgroud)

说明:

要查找连续三个系列,您只需要将第2个到第2个到第2个的每个元素与它之前和之后的邻居进行比较.

由于您的值是0 / 1,它们是有效的T / F,这使得评估非常简单(假设没有NA).

如果v你的值(没有NA),那么!v & !v[-1]在元素及其后继者为0的任何地方都将为TRUE.加入& !v[-(1:2)]并且只要你有三个系列的中间,这将是真的0s. 请注意,这也会捕获一系列4+ 0s!

然后剩下的就是(1)计算上述内容同时删除(并计算!)任何NA,以及(2)按id值分离.幸运的是,data.table使这些变得轻而易举.

结果:

  > myOriginalDf

    row value id isMidPoint
 1:   1     1  x      FALSE
 2:   2     1  x      FALSE
 3:   3     0  x      FALSE
 4:   4     0  x      FALSE
 5:   5     1  x      FALSE
 6:   6     0  x      FALSE
 7:   7     0  x       TRUE  <~~~~
 8:   9     0  x      FALSE
 9:  10     1  x      FALSE
10:  11     0  x      FALSE
11:  12     0  x       TRUE  <~~~~
12:  13     0  x       TRUE  <~~~~
13:  14     0  x       TRUE  <~~~~
14:  15     0  x      FALSE
15:  16     1  y      FALSE
16:  17     0  y      FALSE
17:  18     0  y       TRUE  <~~~~
18:  20     0  y      FALSE
19:  21     1  y      FALSE
20:  22     1  y      FALSE
21:  23     0  y      FALSE
22:  25     0  y       TRUE  <~~~~
23:  27     0  y       TRUE  <~~~~
24:  29     0  y      FALSE
    row value id isMidPoint
Run Code Online (Sandbox Code Playgroud)

根据评论编辑:

如果要查找真正使用最后一个序列:

    max(which(myOriginalDf$isMidpoint))
Run Code Online (Sandbox Code Playgroud)

如果你想知道真正使用的最后一个序列:

  # Will be TRUE if last possible sequence is 0-0-0
  #   Note, this accounts for NA's as well
  myOriginalDf[!is.na(value), isMidpoint[length(isMidpoint)-1]
Run Code Online (Sandbox Code Playgroud)

  • @ManoelGaldino,你可以使用`max(which(isMidpoint))`告诉你最后的顺序是真的. (2认同)