R выбрать последовательность определенной длины

#r

#r

Вопрос:

Я пытаюсь выяснить, как выбирать последовательности длиной 3.

Рассмотрим следующую двоичную последовательность.

 sq
1   0
2   0
3   0
4   1
5   1
6   0
7   0
8   1
9   1
10  1
11  1
12  0
13  0
14  0
15  1
16  1
17  0
18  1
19  1
20  1
21  1
  

Сначала я хотел бы определить последовательность длиной 3.

Я пытался использовать:

 new = sqd %>% group_by(sq) %>% mutate(sq_cum = cumsum(sq)) %>% as.data.frame()
  

Но это суммирует все числа 1 в последовательности, а не последовательные 1 .

Чего я хочу, так это этого вектора seq_of_three .

    sq sq_cum seq_of_three
1   0      0            0
2   0      0            0
3   0      0            0
4   1      1            0
5   1      2            0
6   0      0            0
7   0      0            0
8   1      3            1
9   1      4            1
10  1      5            1
11  1      6            1
12  0      0            0
13  0      0            0
14  0      0            0
15  1      7            0
16  1      8            0
17  0      0            0
18  1      9            1
19  1     10            1
20  1     11            1
21  1     12            1
  

Как только я получу это, я хотел бы подмножество 3 первых последовательностей.

    sq sq_cum seq_of_three
8   1      3            1
9   1      4            1
10  1      5            1
18  1      9            1
19  1     10            1
20  1     11            1
  

данные

 structure(list(sq = c(0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 
0, 1, 1, 0, 1, 1, 1, 1), sq_cum = c(0, 0, 0, 1, 2, 0, 0, 3, 4, 
5, 6, 0, 0, 0, 7, 8, 0, 9, 10, 11, 12), seq_of_three = c(0, 0, 
0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1)), row.names = c(NA, 
-21L), class = "data.frame")
  

Комментарии:

1. @akrun, извините, я имел в виду последовательность из единиц. Я имею в виду последовательность из единиц длиной 3. Имеет ли это смысл?

2. Я вижу, что строки 8, 9, 10, 11 являются единицами, но единственная последовательность из трех равна 8, 9, 10. Строка 11 не включена, хотя она находится в последовательности строк 9, 10 11. Все в порядке — вам нужны по крайней мере неперекрывающиеся последовательности. Но обязательно ли между ними должны быть 0? То есть, если у вас было шесть единиц подряд, это 2 последовательности по 3 или просто 1?

Ответ №1:

Мы можем использовать rleid для создания переменной группировки, а затем создать последовательность из трех, проверив количество строк и значения ‘sq’, чтобы создать двоичный столбец, filter строки, имеющие ‘seq_of_three’ как 1, а затем slice первые 3 строки. При необходимости удалите столбец ‘grp’

 library(dplyr)
library(data.table)
sqd %>%
  group_by(grp = rleid(sq)) %>% 
  mutate(seq_of_three =   (n() > 3 amp; all(sq == 1))) %>%
  filter(seq_of_three  == 1) %>%
  slice(1:3) %>%
  ungroup %>%
  select(-grp)
# A tibble: 6 x 3
#     sq sq_cum seq_of_three
#  <dbl>  <dbl>        <int>
#1     1      3            1
#2     1      4            1
#3     1      5            1
#4     1      9            1
#5     1     10            1
#6     1     11            1
  

ПРИМЕЧАНИЕ: Неясно, нужно ли нам seq_of_three создавать столбец или нет. Если нет, то шаги можно дополнительно сделать компактными


Другой вариант с slice

 sqd %>%
   group_by(grp = rleid(sq)) %>%
   mutate(seq_of_three =   (n() > 3 amp; all(sq == 1))) %>% 
   slice(head(row_number()[seq_of_three  == 1], 3)) %>%
   ungroup %>%
   select(-grp)
  

Комментарии:

1. интересно, как бы тогда вы подмножествовали 3 первых эпизода?

2. @giacomo Извините, я думал о промежуточном выводе. Теперь вы получите подмножество ожидаемых выходных данных

3. Я думаю, что это хорошо иметь seq_of_tree для того, чтобы дважды проверить данные

Ответ №2:

Другая dplyr возможность может быть:

 df %>%
 rowid_to_column() %>%
 group_by(grp = with(rle(sq), rep(seq_along(lengths), lengths))) %>%
 mutate(grp_seq = seq_along(grp)) %>%
 filter(sq == 1 amp; grp_seq %in% 1:3 amp; length(grp) >= 3) 

  rowid    sq   grp grp_seq
  <int> <int> <int>   <int>
1     8     1     4       1
2     9     1     4       2
3    10     1     4       3
4    18     1     8       1
5    19     1     8       2
6    20     1     8       3
  

Здесь, во-первых, используется rleid() подобная функция для создания переменной группировки. Во-вторых, это создает последовательность по этой группирующей переменной. Наконец, сохраняются случаи, когда «sq» == 1, длина переменной группировки равна трем или более, а последовательность вокруг переменных группировки имеет значения от одного до трех.

Комментарии:

1. Я не могу толком понять код, но он хорошо работает с моими данными. Что rowid_to_column() и rle делает?

2. rowid_to_column() Строка приведена просто для того, чтобы показать, что она действительно содержит нужные вам строки. Для других строк, пожалуйста, смотрите обновленный пост.

Ответ №3:

 replace(ave(df1$sq, df1$sq, FUN = seq_along), df1$sq == 0, 0)
# [1]  0  0  0  1  2  0  0  3  4  5  6  0  0  0  7  8  0  9 10 11 12

with(rle(df1$sq), {
    rep(replace(rep(0, length(values)), lengths >= 3 amp; values == 1, 1), lengths)
})
# [1] 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 1 1 1 1

df1[with(rle(df1$sq), {
    temp = rep(replace(rep(0, length(values)),
                       lengths >= 3 amp; values == 1,
                       seq(sum(lengths >= 3 amp; values == 1))),
               lengths)
    ave(temp, temp, FUN = seq_along) <= 3 amp; temp > 0
}),]
#   sq sq_cum seq_of_three
#8   1      3            1
#9   1      4            1
#10  1      5            1
#18  1      9            1
#19  1     10            1
#20  1     11            1