Как создать новый столбец со значениями из предыдущей строки в существующем столбце, в tibble, в R

#r #loops #bigdata #tibble

#r #циклы #bigdata #tibble

Вопрос:

Я хочу создать новый столбец, который состоит из последнего значения из предыдущего периода для того же идентификатора, помещенного в ту же строку, что и первое значение для следующего периода. Если предыдущего периода нет, следует применить NA.

Однако я не могу найти никаких функций ни в каких пакетах, чтобы решить эту проблему для меня, поэтому я ожидаю, что мне придется написать цикл?

Есть ли у кого-нибудь идеи, как решить это аккуратным способом (с циклом или без него), который можно применить к большому tibble ( 4 миллиона наблюдений)?

Мои данные упорядочены как следующий df, а цель — df1:

 df <- tibble(
  ID = rep(c(77,88,99),each=6),
  PERIOD = rep(c(1,2,3,1,2,3,1,2,3),each=2),
  DATE = seq(as.Date("2020-06-01"), as.Date("2020-06-18"), by= "days"),
  RESULT = seq(from = 10, to = 44, by = 2)
)
df
# A tibble: 18 x 4
      ID PERIOD DATE       RESULT
   <dbl>  <dbl> <date>      <dbl>
 1    77      1 2020-06-01     10
 2    77      1 2020-06-02     12
 3    77      2 2020-06-03     14
 4    77      2 2020-06-04     16
 5    77      3 2020-06-05     18
 6    77      3 2020-06-06     20
 7    88      1 2020-06-07     22
 8    88      1 2020-06-08     24
 9    88      2 2020-06-09     26
10    88      2 2020-06-10     28
11    88      3 2020-06-11     30
12    88      3 2020-06-12     32
13    99      1 2020-06-13     34
14    99      1 2020-06-14     36
15    99      2 2020-06-15     38
16    99      2 2020-06-16     40
17    99      3 2020-06-17     42
18    99      3 2020-06-18     44

df1 <- tibble(
  ID = rep(c(77,88,99),each=6),
  PERIOD = rep(c(1,2,3,1,2,3,1,2,3),each=2),
  DATE = seq(as.Date("2020-06-01"), as.Date("2020-06-18"), by= "days"),
  RESULT = seq(from = 10, to = 44, by = 2),
  RESULT_post = c("NA","NA",12,"NA",16,"NA","NA","NA",24,"NA",28, 
                  "NA","NA", "NA",36, "NA",40, "NA" )
)
df1

# A tibble: 18 x 5
      ID PERIOD DATE       RESULT RESULT_pre
   <dbl>  <dbl> <date>      <dbl> <chr>     
 1    77      1 2020-06-01     10 NA        
 2    77      1 2020-06-02     12 NA        
 3    77      2 2020-06-03     14 12        
 4    77      2 2020-06-04     16 NA        
 5    77      3 2020-06-05     18 16        
 6    77      3 2020-06-06     20 NA        
 7    88      1 2020-06-07     22 NA        
 8    88      1 2020-06-08     24 NA        
 9    88      2 2020-06-09     26 24        
10    88      2 2020-06-10     28 NA        
11    88      3 2020-06-11     30 28        
12    88      3 2020-06-12     32 NA        
13    99      1 2020-06-13     34 NA        
14    99      1 2020-06-14     36 NA        
15    99      2 2020-06-15     38 36        
16    99      2 2020-06-16     40 NA        
17    99      3 2020-06-17     42 40        
18    99      3 2020-06-18     44 NA
  

Все входные данные приветствуются

Спасибо / Sophia

Ответ №1:

Вот способ с dplyr :

 library(dplyr)

df %>%
  group_by(ID, PERIOD) %>%
  summarise(RESULT_pre = last(RESULT)) %>%
  mutate(RESULT_pre = lag(RESULT_pre)) %>%
  left_join(df, by = c('ID', 'PERIOD')) %>%
  group_by(ID, PERIOD) %>%
  mutate(RESULT_pre = replace(RESULT_pre, -1, NA)) %>%
  select(-RESULT_pre, RESULT_pre)

#      ID PERIOD DATE       RESULT RESULT_pre
#   <dbl>  <dbl> <date>      <dbl>      <dbl>
# 1    77      1 2020-06-01     10         NA
# 2    77      1 2020-06-02     12         NA
# 3    77      2 2020-06-03     14         12
# 4    77      2 2020-06-04     16         NA
# 5    77      3 2020-06-05     18         16
# 6    77      3 2020-06-06     20         NA
# 7    88      1 2020-06-07     22         NA
# 8    88      1 2020-06-08     24         NA
# 9    88      2 2020-06-09     26         24
#10    88      2 2020-06-10     28         NA
#11    88      3 2020-06-11     30         28
#12    88      3 2020-06-12     32         NA
#13    99      1 2020-06-13     34         NA
#14    99      1 2020-06-14     36         NA
#15    99      2 2020-06-15     38         36
#16    99      2 2020-06-16     40         NA
#17    99      3 2020-06-17     42         40
#18    99      3 2020-06-18     44         NA
  

Логика здесь заключается в том, чтобы суммировать last RESULT значение для каждого ID и PERIOD и использовать lag для сдвига значения в каждом ID . Мы объединяем этот результат с исходным набором данных и сохраняем только первое значение в каждой группе и заменяем все остальные значения на NA .

Ответ №2:

Вы можете скопировать все сдвинутые значения и перезаписать те, которые не соответствуют NA :

 n <- nrow(df)
df$RESULT_pre <- c(NA, df$RESULT[-n])
df$RESULT_pre[c(FALSE, df$ID[-1] != df$ID[-n] |
   df$PERIOD[-1] == df$PERIOD[-n])] <- NA
df
#   ID PERIOD       DATE RESULT RESULT_pre
#1  77      1 2020-06-01     10         NA
#2  77      1 2020-06-02     12         NA
#3  77      2 2020-06-03     14         12
#4  77      2 2020-06-04     16         NA
#5  77      3 2020-06-05     18         16
#6  77      3 2020-06-06     20         NA
#7  88      1 2020-06-07     22         NA
#8  88      1 2020-06-08     24         NA
#9  88      2 2020-06-09     26         24
#10 88      2 2020-06-10     28         NA
#11 88      3 2020-06-11     30         28
#12 88      3 2020-06-12     32         NA
#13 99      1 2020-06-13     34         NA
#14 99      1 2020-06-14     36         NA
#15 99      2 2020-06-15     38         36
#16 99      2 2020-06-16     40         NA
#17 99      3 2020-06-17     42         40
#18 99      3 2020-06-18     44         NA