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)
这是一个基于您的矢量解决方案的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)
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)