使用 dplyr 在多列上按组插入 NA

avs*_*avs 5 r zoo na dplyr

我有一个这样的数据框:

> head(df1)
  iso year var1 var2 var3
1 XXX 2005  165   29 2151
2 XXX 2006  160   21 2139
3 XXX 2007   NA   NA   NA
4 XXX 2008  184    9 3640
5 XXX 2009   NA   NA   NA
6 YYY 2005  206  461 8049 
Run Code Online (Sandbox Code Playgroud)

我想通过向后和向前进行最外面的非 NA 观察来替换NA基于周围年份的间歇年份NA以及范围开始和结束的年份。

我为一列执行此操作的代码是:

df1 %>% 
 group_by(iso) %>%
 mutate(var1 = na.approx(var1, na.rm = FALSE, rule = 1)) %>%
 mutate(var1 = na.locf(var1, na.rm = FALSE)) %>%
 mutate(var1 = na.locf(var1, na.rm = FALSE, fromLast = TRUE))
Run Code Online (Sandbox Code Playgroud)

这是有效的,所以现在我想一次性对所有列执行此操作(有 3 个以上,并且它们没有像我的示例中那样编号)。这是我从这个问题的答案中拼凑出来的。我省略了对 的两次调用na.locf

columnnames <- c("var1, "var2", "var3")
df1 %>%
 group_by(iso) %>%
 mutate_at(.vars = vars(columnnames), .funs = funs(na.approx(., na.rm = FALSE, rule = 1)))
Run Code Online (Sandbox Code Playgroud)

这会给我一个错误和警告:

approx(x[!na], y[!na], xout, ...) 中的错误:需要至少两个非 NA 值进行插值另外:警告消息:在 xy.coords(x, y, setLab = FALSE) : 由强制引入的 NA

我想我理解错误,但是当我在var1. 我不遵循的警告。如何将代码应用到数据框中的所有列?我还尝试将所有内容放入循环中,循环,columnnames但这也不起作用(这可能不是解决此问题的最佳方法)。

MKR*_*MKR 2

您可以使用以下方式重写代码mutate_at,以便可以一次性完成转换:

library(dplyr)
library(zoo)


df %>% 
  group_by(iso) %>%
  mutate_at(vars(starts_with("var")), 
            funs(na.locf(na.locf(na.approx(., na.rm = FALSE, rule = 1),na.rm=FALSE),
                                                              fromLast=TRUE)))


# # A tibble: 6 x 5
# # Groups: iso [2]
# iso    year  var1   var2  var3
# <chr> <int> <dbl>  <dbl> <dbl>
# 1 XXX    2005   165  29.0   2151
# 2 XXX    2006   160  21.0   2139
# 3 XXX    2007   172  15.0   2890
# 4 XXX    2008   184   9.00  3640
# 5 XXX    2009   184   9.00  3640
# 6 YYY    2005   206 461     8049
# 
Run Code Online (Sandbox Code Playgroud)

数据:

df <- read.table(text=
"iso year var1 var2 var3
1 XXX 2005  165   29 2151
2 XXX 2006  160   21 2139
3 XXX 2007   NA   NA   NA
4 XXX 2008  184    9 3640
5 XXX 2009   NA   NA   NA
6 YYY 2005  206  461 8049",
header = TRUE, stringsAsFactors = FALSE)
Run Code Online (Sandbox Code Playgroud)