Замените значения NA на сумму предыдущего значения и текущего значения в другом столбце. - PullRequest
0 голосов
/ 18 февраля 2019

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

library(lubridate)
library(tidyverse)
library(zoo)
df <- tibble(
  Id = c(1, 1, 1, 1, 2, 2, 2, 2),
  Time = ymd(c("2012-09-01", "2012-09-02", "2012-09-03", "2012-09-04", "2012-09-01", "2012-09-02", "2012-09-03", "2012-09-04")),
  av = c(18, NA, NA, NA, 21, NA, NA, NA),
  Value = c(121, NA,NA, NA, 146, NA, NA, NA)
)

# A tibble: 8 x 4
Id      Time       av   Value
<dbl>  <date>     <dbl> <dbl>
1     2012-09-01    18   121
1     2012-09-02    NA    NA
1     2012-09-03    NA    NA
1     2012-09-04    NA    NA
2     2012-09-01    21   146
2     2012-09-02    NA    NA
2     2012-09-03    NA    NA
2     2012-09-04    NA    NA

Что я хочу сделать: где Value равно NA, я хочу заменить его на сумму предыдущих Value и текущего значения av.Если av равно NA, его можно заменить предыдущим значением.Я использую функцию na.locf из пакета zoo как

df1 <- df %>% arrange(Id, Time) %>% group_by(Id) %>% 
     mutate(av = zoo::na.locf(av))  

Однако заполнение для Value кажется трудным.Я могу сделать это, используя цикл for как

# Back up the Value column for testing
df1$Value_backup <- df1$Value

for(i in 2:nrow(df1))
{
  df1$Value[i] <- ifelse(is.na(df1$Value[i]), df1$av[i] + df1$Value[i-1], df1$Value[i])

}

Это дает желаемый результат, но для большого набора данных я считаю, что есть лучшие способы сделать это в R. Я попробовал функцию complete изdplyr, но добавляет две дополнительные строки:

df1 <- df %>% arrange(Id, Time) %>% group_by(Id) %>% mutate(av = zoo::na.locf(av)) %>% 
  mutate(num_rows = n()) %>%
  complete(nesting(Id), Value = seq(min(Value, na.rm = TRUE), 
                                    (min(Value, na.rm = TRUE) + max(num_rows) * min(na.omit(av))), min(na.omit(av))))

В выводе есть две дополнительные строки;10 вместо 8

# A tibble: 10 x 5
# Groups:   Id [2]
Id    Value Time         av    num_rows
<dbl> <dbl> <date>     < dbl>    <int>
1     121   2012-09-01    18        4
1     139   NA            NA       NA
1     157   NA            NA       NA
1     175   NA            NA       NA
1     193   NA            NA       NA
2     146   2012-09-01    21        4
2     167   NA            NA       NA
2     188   NA            NA       NA
2     209   NA            NA       NA
2     230   NA            NA       NA

Любая помощь, чтобы сделать это быстрее без петель будет принята с благодарностью.

1 Ответ

0 голосов
/ 18 февраля 2019

В вопросе av начинается с не-NA в каждой группе, и за ним следуют NA, поэтому, если это общая схема, это сработает.Обратите внимание, что это хорошая форма, чтобы закрыть любой group_by с ungroup;однако ниже мы этого не сделали, чтобы мы могли сравнить df2 с df1.

df2 <- df %>% 
  group_by(Id) %>% 
  mutate(Value_backup = Value,
         av = first(av), 
         Value = first(Value) + cumsum(av) - av)

identical(df1, df2)
## [1] TRUE

Примечание

Для воспроизводимости сначала запустите это (взято из вопроса, за исключением того, что мы загружаем тольконеобходимые пакеты):

library(dplyr)
library(tibble)
library(lubridate)

df <- tibble(
  Id = c(1, 1, 1, 1, 2, 2, 2, 2),
  Time = ymd(c("2012-09-01", "2012-09-02", "2012-09-03", "2012-09-04", "
    2012-09-01", "2012-09-02", "2012-09-03", "2012-09-04")),
  av = c(18, NA, NA, NA, 21, NA, NA, NA),
  Value = c(121, NA,NA, NA, 146, NA, NA, NA)
)

df1 <- df %>% arrange(Id, Time) %>% group_by(Id) %>% 
     mutate(av = zoo::na.locf(av))  
df1$Value_backup <- df1$Value
for(i in 2:nrow(df1))
{
  df1$Value[i] <- ifelse(is.na(df1$Value[i]), df1$av[i] + df1$Value[i-1], df1$Value[i])

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...