R: счетчик с условиями

#r #dplyr #counter

#r #dplyr #счетчик

Вопрос:

Мне нужна переменная «minus_180_days» / (счетчик), которая должна быть пронумерована в порядке возрастания:

  1. при первом посещении,

  2. если во второй раз прошло менее 180 дней (по сравнению с предыдущим посещением пациента); если 180-дневный критерий не соблюден, 1 также должен появиться при этом втором посещении;

  3. если при третьем посещении прошло менее 180 дней с предыдущего (посещение «2»), если критерий в 180 дней не соблюден, 1 при этом третьем посещении и т. Д

Данные

 pacient <- c(10,10,10,10,10,11,11,12,12,12,13, 13, 15, 14); pacient
date <- as.Date(c("01/01/2018","02/05/2018", "04/06/2018", "10/11/2019", "05/12/2018", "02/01/2018", "06/08/2018", "01/01/2018", "03/01/2018", "06/03/2018", "05/08/2018", "05/08/2019", "05/07/2019", "08/07/2017"), format = "%d/%m/%Y"); date 
DF <- data.frame(pacient, date); DF
  

У меня есть этот код

 DF <- DF %>%
  group_by(pacient) %>%
  arrange(date) %>%
  mutate(days_visit = date - lag(date, default = first(date))) 
days_visit <- as.integer(DF$days_visit) 

DF <- DF[with(DF,order(pacient,date)),]
  

Результат, который мне нужен (ожидаемый результат)
вывод, который мне нужен

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

1. Можете ли вы вставить ожидаемый результат?

2. Это картинка! «Вывод, который мне нужен …»

Ответ №1:

Решение dplyr, обновленное с учетом полезного комментария @ Gregor:

 DF2 <- DF %>%
  group_by(pacient) %>%
  arrange(pacient, date) %>%
  mutate(days_visit = (date - lag(date, default = first(date))) %>% as.integer,
         new_count = cumsum(days_visit > 180)   1) %>%
  group_by(pacient, new_count) %>%
  mutate(vis_num = row_number(),
         counter = case_when(vis_num == 1      ~ 1L,
                             days_visit < 180  ~ vis_num,
                             TRUE              ~ 1L))
> DF
# A tibble: 14 x 5
# Groups:   pacient [6]
   pacient date       days_visit vis_num counter
     <dbl> <date>          <int>   <int>   <int>
 1      10 2018-01-01          0       1       1
 2      10 2018-05-02        121       2       2
 3      10 2018-06-04         33       3       3
 4      10 2018-12-05        184       4       1
 5      10 2019-11-10        340       5       1
 6      11 2018-01-02          0       1       1
 7      11 2018-08-06        216       2       1
 8      12 2018-01-01          0       1       1
 9      12 2018-01-03          2       2       2
10      12 2018-03-06         62       3       3
11      13 2018-08-05          0       1       1
12      13 2019-08-05        365       2       1
13      14 2017-07-08          0       1       1
14      15 2019-07-05          0       1       1
  

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

1. Абсолютно верно. Мне просто понравилось, что счетчик один был «циклом посещения».

Ответ №2:

Немного более сжатый способ (адаптированный от @Gregor) сделать это на основе tidyverse, включая исправление ошибки, указанной @Gregor.

 DF %>%
  arrange(pacient, date) %>%
  group_by(pacient) %>%
  mutate(days_visit = as.integer(date - lag(date, default = first(date))) ,
         less_180 = days_visit < 180,
         counter = ave(less_180, cumsum(less_180 == 0), FUN = seq_along)) 

# A tibble: 17 x 5
# Groups:   pacient [6]
   pacient date       days_visit less_180 counter
     <dbl> <date>          <int>    <dbl>   <dbl>
 1      10 2018-01-01          0        1       1
 2      10 2018-05-02        121        1       2
 3      10 2018-06-04         33        1       3
 4      10 2018-12-05        184        0       1
 5      10 2019-11-10        340        0       1
 6      10 2019-11-11          1        1       2
 7      10 2019-11-12          1        1       3
 8      10 2019-11-13          1        1       4
 9      11 2018-01-02          0        1       1
10      11 2018-08-06        216        0       1
11      12 2018-01-01          0        1       1
12      12 2018-01-03          2        1       2
13      12 2018-03-06         62        1       3
14      13 2018-08-05          0        1       1
15      13 2019-08-05        365        0       1
16      14 2017-07-08          0        1       1
17      15 2019-07-05          0        1       1
  

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

1. Мой комментарий к ответу Джона применим и здесь: я не думаю, что это будет обобщать далеко за пределы выборочных данных OP. Если пациентка 10 передаст другую строку с датой 2019-11-11 , логическая операция, описанная в, даст ей значение счетчика 2 , но это решение даст ему 4 .

2. Смотрите мой ответ для примера данных, в котором у pacient 10 есть дополнительные строки.

3. Да, это имеет смысл

4. Кажется очень странным использовать ave внутри mutate . dplyr Способ был бы ... %>% group_by(pacient, grouper = cumsum(less_180 == 0)) %>% mutate(counter = row_number()) (я думаю… не тестировался)

Ответ №3:

Кажется, это работает:

 library(data.table)
setDT(DF)
setorder(DF, pacient, date)

DF[, v := rowid(pacient, cumsum(date - shift(date, fill=first(date)) > 180))]

    pacient       date v
 1:      10 2018-01-01 1
 2:      10 2018-05-02 2
 3:      10 2018-06-04 3
 4:      10 2018-12-05 1
 5:      10 2019-11-10 1
 6:      11 2018-01-02 1
 7:      11 2018-08-06 1
 8:      12 2018-01-01 1
 9:      12 2018-01-03 2
10:      12 2018-03-06 3
11:      13 2018-08-05 1
12:      13 2019-08-05 1
13:      14 2017-07-08 1
14:      15 2019-07-05 1
  

Тестирование с использованием более сложных данных Грегора…

 pacient2 <- c(10,10,10,10,10,10,10,10,11,11,12,12,12,13, 13, 15, 14)
date2 <- as.Date(c("01/01/2018","02/05/2018", "04/06/2018", "10/11/2019", "11/11/2019", "12/11/2019", "13/11/2019", "05/12/2018", "02/01/2018", "06/08/2018", "01/01/2018", "03/01/2018", "06/03/2018", "05/08/2018", "05/08/2019", "05/07/2019", "08/07/2017"), format = "%d/%m/%Y")
DF2 <- data.frame(pacient = pacient2, date = date2)

library(data.table)
setDT(DF2)
setorder(DF2, pacient, date)

DF2[, v := rowid(pacient, cumsum(date - shift(date, fill=first(date)) > 180))]

    pacient       date v
 1:      10 2018-01-01 1
 2:      10 2018-05-02 2
 3:      10 2018-06-04 3
 4:      10 2018-12-05 1
 5:      10 2019-11-10 1
 6:      10 2019-11-11 2
 7:      10 2019-11-12 3
 8:      10 2019-11-13 4
 9:      11 2018-01-02 1
10:      11 2018-08-06 1
11:      12 2018-01-01 1
12:      12 2018-01-03 2
13:      12 2018-03-06 3
14:      13 2018-08-05 1
15:      13 2019-08-05 1
16:      14 2017-07-08 1
17:      15 2019-07-05 1
  

Я получаю другой результат, но, похоже, это имеет смысл. Дайте мне знать, если возникнут проблемы, кто-нибудь.

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

1. Я думаю, что ваш результат правильный, а мой — с ошибкой.