用不同列中的先前值和当前值之和替换NA的值

时间:2019-02-17 21:43:22

标签: r dplyr na missing-data

我有一个数据集,其中我必须使用另一列中的先前值和当前值之和来填充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

我想做的是:在ValueNA的地方,我想用之前的Value和当前值av的总和来代替它。如果avNA,则可以将其替换为先前的值。我将Zoo软件包中的na.locf函数用作

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的{​​{1}}函数,但它添加了另外两行: / p>

dplyr

输出有两个额外的行; 10而不是8

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))))

任何帮助您更快地完成而不循环的帮助。

1 个答案:

答案 0 :(得分:1)

在问题av中,每个组均以非NA开头,后跟NA,因此,如果这是一般模式,则可以使用。注意,用group_by关闭任何ungroup是一种很好的形式;但是,我们在下面没有这样做,因此我们可以将df2df1进行比较。

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])

}