如何找到一行中有 n 个连续零的索引
How to find the indices where there are n consecutive zeroes in a row
假设我有这个数据:
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 表示第一个零等
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]
这里有两种基本的 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
通过使用 dplyr
,得到 diff
然后如果 diff 不等于 0 ,它们不属于同一组,在 cumsum
之后我们得到 grouid
library(dplyr)
df=data.frame('x'=x,rownumber=seq(length(x)))
df$Groupid=cumsum(c(0,diff(df$x==0))!=0)
df%>%group_by(Groupid)%>%summarize(start=first(rownumber),end=last(rownumber),number=first(x),size=n())%>%filter(number==0&size>=3)
# A tibble: 3 x 5
Groupid start end number size
<int> <int> <int> <dbl> <int>
1 1 6 17 0 12
2 3 34 58 0 25
3 5 72 89 0 18
如果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)]
根据 rleid(x)
对 dt
进行分区,并为 dt
的行的每个子集计算 <code>
。结果叠加在一个 data.table
.
中
.N
是给定子集中的元素个数
.I
是子集对应的行号向量
first
和 last
给出向量的第一个和最后一个元素
.(<stuff>)
等同于 list(<stuff>)
rleid
函数,by
括号内的分组,.N和.I符号,first
和last
函数是[=12=的一部分] 包。
假设我有这个数据:
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 表示第一个零等
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]
这里有两种基本的 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
通过使用 dplyr
,得到 diff
然后如果 diff 不等于 0 ,它们不属于同一组,在 cumsum
之后我们得到 grouid
library(dplyr)
df=data.frame('x'=x,rownumber=seq(length(x)))
df$Groupid=cumsum(c(0,diff(df$x==0))!=0)
df%>%group_by(Groupid)%>%summarize(start=first(rownumber),end=last(rownumber),number=first(x),size=n())%>%filter(number==0&size>=3)
# A tibble: 3 x 5
Groupid start end number size
<int> <int> <int> <dbl> <int>
1 1 6 17 0 12
2 3 34 58 0 25
3 5 72 89 0 18
如果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)]
根据rleid(x)
对dt
进行分区,并为dt
的行的每个子集计算<code>
。结果叠加在一个data.table
..N
是给定子集中的元素个数.I
是子集对应的行号向量first
和last
给出向量的第一个和最后一个元素.(<stuff>)
等同于list(<stuff>)
rleid
函数,by
括号内的分组,.N和.I符号,first
和last
函数是[=12=的一部分] 包。