【问题标题】:Replace the values of NA with a sum of previous value and a current value in different column用不同列中先前值和当前值的总和替换 NA 的值
【发布时间】:2019-02-17 21:43:22
【问题描述】:

我有一个数据集,我必须使用前一个值和另一列中当前值的总和来填充 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,我想用以前的Valueav 的当前值替换它。如果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 中有更好的方法可以做到这一点。我尝试了 dplyr 中的 complete 函数,但它增加了两行:

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

如果能在没有循环的情况下更快地完成此任务,我们将不胜感激。

【问题讨论】:

  • 这对您的实际问题有帮助吗df1 %&gt;% group_by(Id) %&gt;% mutate(Value2 = replace(Value, is.na(Value), lag(Value) + av))
  • @markus: 不是真的,因为它只在找到值后的一行中为NA 填充一个值。
  • “在没有循环的情况下更快地完成它的任何帮助” 这是一个不幸的神话,for 循环在 R 中是坏的/慢的;在您的情况下,它应该非常快,因为您不是动态增长向量,而是仅根据条件替换值。我想这里的瓶颈是ifelse,它与for 循环无关。

标签: r dplyr na missing-data


【解决方案1】:

在问题av 中,每个组都以非 NA 开头,然后是 NA,因此如果这是一般模式,那么这将起作用。请注意,最好用ungroup 关闭任何group_by;但是,我们没有在下面这样做,以便我们可以比较 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])

}

【讨论】:

    猜你喜欢
    • 2019-03-24
    • 1970-01-01
    • 2020-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-01
    • 1970-01-01
    相关资源
    最近更新 更多