Как найти индексы, где есть n последовательных нулей подряд - PullRequest
0 голосов
/ 13 мая 2018

Предположим, у меня есть эти данные:

  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 за первую ноль и т. Д.

Ответы [ 4 ]

0 голосов
/ 13 мая 2018

Если 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 указывает, к какому «run» относится элемент, где «run» означает последовательность смежных равных значений.
  • dt[, <code>, by = rle(x)] разбиений dt в соответствии с rleid(x) и вычисляет<code> для каждого подмножества строк dt.Результаты объединены в один data.table.
  • .N - количество элементов в данном подмножестве
  • .I - вектор номеров строк, соответствующих подмножеству
  • first и lastдать первый и последний элемент вектора
  • .(<stuff>) совпадает с list(<stuff>)

    Функция rleid, by группировка в скобках, .Nи символы .I, функции first и last являются частью пакета data.table.

0 голосов
/ 13 мая 2018

Вот два базовых подхода 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
0 голосов
/ 13 мая 2018

Используя 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
0 голосов
/ 13 мая 2018
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]
...