R 将间歇性 NA 值替换为结转的最后一个观察值 (NA.LOCF)

R Replace Intermittent NA Values With Last Observation Carried Forward (NA.LOCF)

背景

我需要根据 NA 的性质使用不同的方法来替换我的数据框中的 NA。我的数据框来自一项重复测量的研究,其中一些 Na 是受试者退出的结果,而另一些则是间歇性缺失测量的结果,定义为一个或一系列多个缺失测量,后跟一个测量值。 我将间歇性缺失测量称为间歇性 NA。

问题

我无法测试 NA 是否是间歇性缺失测量的结果,以及我应该使用什么函数来替换这些 NA。理想情况下,我会用 na.locf 方法替换这些间歇性的 NA。但我需要将 Dropout NA 替换为基线或最后观察到的值,以较大者为准。

例子

例1

这是一个干净的 NA 示例,我希望将其视为具有 na.locf 插补的间歇性 NA:

data.frame(visit=c(1,2,3,4,5,6,7,8,9,10),value=c(34,NA,NA,15,16,19,NA,12,23,31))

以及我希望最终结果如何:

data.frame(visit=c(1,2,3,4,5,6,7,8,9,10),value=c(34,34,34,15,16,19,19,12,23,31))

例2

这里是一个干净的 NA (dropout NA) 示例,我想通过之前的非 NA 观察或基线值(访问 1)估算,以最大者为准:

data.frame(visit=c(1,2,3,4,5,6,7,8,9,10),value=c(34,22,18,15,16,19,NA,NA,NA,NA))

我希望最终结果如何:

data.frame(visit=c(1,2,3,4,5,6,7,8,9,10),value=c(34,22,18,15,16,19,34,34,34,34))

例3

这是一个复杂的 NA 混合示例,需要不同的插补,这里先前的非 NA 观察值大于 dropout NA 的基线观察值(访问 1):

data.frame(visit=c(1,2,3,4,5,6,7,8,9,10),value=c(34,NA,NA,42,16,19,NA,38,NA,NA))

我需要的结果是:

data.frame(visit=c(1,2,3,4,5,6,7,8,9,10),value=c(34,34,34,42,16,19,19,38,38,38))

例4

另一个复杂的例子,其中基线观察(访问 1)大于先前的非 NA 值,用于 dropout NA:

data.frame(visit=c(1,2,3,4,5,6,7,8,9,10),value=c(40,NA,NA,42,16,19,NA,38,NA,NA))

我需要的结果是:

data.frame(visit=c(1,2,3,4,5,6,7,8,9,10),value=c(40,40,40,42,16,19,19,38,40,40))

我试过的

正如@Gregor 所建议的,当我说这将解决我的问题时,可以使用以下方法测试间歇性 NA 的存在:

mutate(is.na(value) & !is.na(lead(value))

但这并不能帮助我估算所有间歇性 NA,特别是序列 (NA1,NA2,NA3,14) 中的间歇性 NA,其中在 运行 之后只有 NA3 返回 TRUE这个测试。

我们可以使用 na.locf(..., fromLast = TRUE) 来识别尾随 NA 值,并将 pmax 与基线一起使用。我们将以一种很好的整体格式演示您问题中的示例:

# consolidate example data
dd = data.frame(
  example = rep(1:3, each = 10),
  visit = rep(1:10, 3),
  value = c(34,NA,NA,15,16,19,NA,12,23,31,
            34,22,18,15,16,19,NA,NA,NA,NA,
            34,NA,NA,42,16,19,NA,38,NA,NA),
  goal = c(34,34,34,15,16,19,19,12,23,31,
           34,22,18,15,16,19,34,34,34,34,
           34,34,34,42,16,19,19,38,38,38)
)

library(dplyr)
dd = dd %>% group_by(example) %>%
  mutate(to_fill = !is.na(zoo::na.locf(value, fromLast = TRUE, na.rm = FALSE)),
         result = if_else(to_fill,
                          zoo::na.locf(value, na.rm = FALSE),
                          pmax(first(value), zoo::na.locf(value, na.rm = FALSE))),
    )

all(dd$goal == dd$result)
# [1] TRUE

如您所见,resultgoal 列完美匹配。