#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