Определите последовательности на основе запуска переменной с дополнительным условием из другой переменной - PullRequest
0 голосов
/ 15 сентября 2018
structure(list(group = c(NA, "A", "B", NA, "B", "B", "B", "B", 
"B", "B", "B", "B", "B", "B", "B", "B", "B", "B", "B", "B", "B", 
"B", NA, NA, "B", "B", "A", "A", NA, NA, "B", "B", "B", NA, "A", 
"A", "A", "A", "A", "A", "A", "A", "A", "A", NA, NA, "B", "B", 
NA, "A"), seq_break = c(TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, 
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, 
TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, 
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 
FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE)), .Names = c("group", 
"seq_break"), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, 
-50L))

В вышеприведенных данных мне нужно определить столбец, который будет содержать идентификатор типа длины строки столбца group (например, data.table::rleid производит, но игнорирует NA). Как вы можете заметить, у нас есть также столбец seq_break, который должен завершать последовательность. И это обычно так, например, когда group = NA, затем seq_break = TRUE. Но иногда seq_break = TRUE и группа A или B - тогда последовательность должна быть закончена, и начинается новая, даже если следующая строка относится к той же группе. Так, например, для строк 25:26 у нас должно быть два разных идентификатора последовательности, даже если оба события относятся к группе B. Как правило, ожидаемый результат показан ниже:

structure(list(group = c(NA, "A", "B", NA, "B", "B", "B", "B", 
"B", "B", "B", "B", "B", "B", "B", "B", "B", "B", "B", "B", "B", 
"B", NA, NA, "B", "B", "A", "A", NA, NA, "B", "B", "B", NA, "A", 
"A", "A", "A", "A", "A", "A", "A", "A", "A", NA, NA, "B", "B", 
NA, "A"), seq_break = c(TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, 
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, 
TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, 
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 
FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE), expected_output = c(NA, 
1, 2, NA, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 
3, NA, NA, 4, 5, 6, 6, NA, NA, 7, 7, 7, NA, 8, 8, 8, 8, 8, 8, 
8, 8, 8, 8, NA, NA, 11, 11, NA, 12)), .Names = c("group", "seq_break", 
"expected_output"), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, 
-50L))

Как мне добиться этого с tidyverse?

1 Ответ

0 голосов
/ 15 сентября 2018

Решение с использованием tidyverse и data.table.Предположим, dt1 - ваш примерный фрейм данных, а dt3 - окончательный результат.Обратите внимание, что я думаю, что в ожидаемом выводе строки 47–48 должны быть 9, а строка 50 - 10. Я не уверен, почему в ожидаемом выходном ряду 47–48 - 11, а строка 50 - 12.

library(tidyverse)
library(data.table)

dt2 <- dt1 %>% rowid_to_column() 

dt3 <- dt2 %>%
  mutate(ID = rleid(group, seq_break)) %>%
  group_by(group, seq_break, ID) %>%
  filter(!(is.na(group) & seq_break & row_number() > 1)) %>%
  ungroup() %>%
  mutate(ID2 = cumsum(seq_break)) %>%
  drop_na(group) %>%
  mutate(expected_output = rleid(group, ID2)) %>%
  select(rowid, expected_output) %>%
  left_join(dt2, ., by = "rowid") %>%
  select(-rowid)

dt3
# # A tibble: 50 x 3
#    group seq_break expected_output
#    <chr> <lgl>               <int>
#  1 NA    TRUE                   NA
#  2 A     FALSE                   1
#  3 B     FALSE                   2
#  4 NA    TRUE                   NA
#  5 B     FALSE                   3
#  6 B     FALSE                   3
#  7 B     FALSE                   3
#  8 B     FALSE                   3
#  9 B     FALSE                   3
# 10 B     FALSE                   3
# # ... with 40 more rows
...