假设我有这些数据:
x = c(14,14, 6, 7 ,14 , 0 ,0 ,0 , 0, 0, 0 , 0 , 0, 0 , 0 , 0 , 0, 9 ,1 , 3 ,8 ,9 ,15, 9 , 8, 13, 8, 4 , 6 , 7 ,10 ,13, 3,
0 , 0 , 0 , 0 , 0 , 0, 0, 0 , 0 , 0 , 0, 0, 0, 0, 0 ,0, 0 , 0 , 0, 0, 0, 0, 0 , 0, 0, 4 , 7 ,4, 5 ,16 , 5 ,5 , 9 , 4 ,4, 9 , 8, 2, 0 ,0 ,0 ,0 ,0, 0, 0, 0 ,0 , 0, 0, 0, 0, 0, 0, 0, 0,0)
x
[1] 14 14 6 7 14 0 0 0 0 0 0 0 0 0 0 0 0 9 1 3 8 9 15 9 8
[26] 13 8 4 6 7 10 13 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
[51] 0 0 0 0 0 0 0 0 4 7 4 5 16 5 5 9 4 4 9 8 2 0 0 0 0
[76] 0 0 0 0 0 0 0 0 0 0 0 0 0 0
我希望恢复从一行中有超过3个零并且在非零之前以最后0结束的索引。
例如,
我会得到
6,17为第一批零点等等。
答案 0 :(得分:12)
以下是两种基本R方法:
1)rle 首先运行rle
然后计算ok
以选出长度超过3的零序列。然后,我们计算所有重复序列的starts
和ends
,并在最后对ok
子序列进行子集化。
with(rle(x), {
ok <- values == 0 & lengths > 3
ends <- cumsum(lengths)
starts <- ends - lengths + 1
data.frame(starts, ends)[ok, ]
})
,并提供:
starts ends
1 6 17
2 34 58
3 72 89
2)gregexpr 取每个数字的符号 - 将为0或1,然后将它们连接成一个长字符串。然后使用gregexpr
查找至少4个零的位置。结果给出了开始和结束可以从加上match.length
属性减去1开始计算。
s <- paste(sign(x), collapse = "")
g <- gregexpr("0{4,}", s)[[1]]
data.frame(starts = 0, ends = attr(g, "match.length") - 1) + g
,并提供:
starts ends
1 6 17
2 34 58
3 72 89
答案 1 :(得分:7)
Starts = which(diff(x == 0) == 1) + 1
Ends = which(diff(x == 0) == -1)
if(length(Ends) < length(Starts)) {
Ends = c(Ends, length(x)) }
Starts
[1] 6 34 72
Ends
[1] 17 58 89
这适用于您的测试数据,但允许任何零序列,包括短序列。为了确保您获得长度至少为n的序列,请添加:
n=3
Long = which((Ends - Starts) >= n)
Starts = Starts[Long]
Ends = Ends[Long]
答案 2 :(得分:5)
如果x
恰好是data.table
的一列,则可以
library(data.table)
dt <- data.table(x = x)
dt[, if(.N > 3 & all(x == 0)) .(starts = first(.I), ends = last(.I))
, by = rleid(x)]
# rleid starts ends
# 1: 5 6 17
# 2: 22 34 58
# 3: 34 72 89
说明:
rleid(x)
为x
中的每个元素指定一个ID(整数)
“运行”元素是其成员,其中“运行”表示序列
相邻的相等值。dt[, <code>, by = rle(x)]
分区dt
,并为rleid(x)
行的每个子集计算<code>
。结果堆叠在一起dt
。 data.table
是给定子集中的元素数量.N
是与子集.I
和first
给出了向量的第一个和最后一个元素 last
与.(<stuff>)
括号内的list(<stuff>)
函数,rleid
分组,.N和.I符号,by
和first
函数是last
包的一部分