首页 > 解决方案 > R 根据 NA 之后的值以及有多少 NA 填充 NA

问题描述

嗨,我想根据 NA 之后的第一个数字和有多少 NA 在我的 data.frame 中填充 NA。这是降雨数据,而 NA 显示仪表未通信的时间,但我们知道该期间发生的总降雨量,并希望对其进行平均。

这里有很多关于如何填充它们的问题,但我没有发现任何需要使用 NA 数量的问题。基本上我想通过丢失的时间步数来平均 NA 之后的数字值。

这是我的示例数据。我做得非常简单,但在实际示例中,我有数十万个条目,并将按站点对数据进行分组。

library(tidyr)
library(dplyr)
library(zoo) 
testdf <- data.frame(DateTime = seq.POSIXt(
  from = as.POSIXct("2019-01-01"), to =  as.POSIXct("2019-01-02"), by = "hours"),
  Value = c(0,0,1,NA,NA,NA,-4,0,0,0,NA,NA,NA,NA,NA,-2,5,3,NA,-2,0,0,0,1,2))

在使用tidyr::fillor之后,我可以轻松地用第一个值填充 NA zoo:na.locf

tidyr::fill(testdf,Value, .direction = "up")

testdf %>% mutate(Filled = zoo::na.locf(Value, fromLast = T))

但我想将其除以连续出现的 NA 数加 1(即,如果有 5 个 NA 除以 6)。理想情况下,我还想将 NA 之后的值更改为也等于这个新值,但如果有必要,我可能会为这一步修改一些东西。

如果有一种简单的方法可以仅针对某些时期的间隙(基本上是 na.locf 的 maxgap 功能)执行此操作,就好像我有一两个小时错过了它的平均值但是如果它是一周或一个月我想要将其保留为 NA。

示例输出

desiredOutput <- data.frame(DateTime = seq.POSIXt(
  from = as.POSIXct("2019-01-01"), to =  as.POSIXct("2019-01-02"), by = "hours"),
  Value = c(0,0,1,-1,-1,-1,-1,0,0,0,-0.33,-0.33,-0.33,-0.33,-0.33,-0.33,5,3,-1,-1,0,0,0,1,2))

标签: rnamissing-data

解决方案


一种使用方法dplyr是创建组,使连续 s 之后的第一个非 NA 值NA包含在组中,这样我们就可以last(Value)将其除以组中的行数(n())。非 NA 的值存储在其单独的组中,只有一个元素,因此它们的计算不受影响,非 NA 数字返回相同的数字。

library(dplyr)

testdf %>%
   group_by(group = lag(cumsum(!is.na(Value)), default = 1)) %>%
   mutate(Value = last(Value)/n()) %>%
   ungroup %>%
   select(-group)

# A tibble: 25 x 2
#   DateTime            Value
#   <dttm>              <dbl>
# 1 2019-01-01 00:00:00     0
# 2 2019-01-01 01:00:00     0
# 3 2019-01-01 02:00:00     1
# 4 2019-01-01 03:00:00    -1
# 5 2019-01-01 04:00:00    -1
# 6 2019-01-01 05:00:00    -1
# 7 2019-01-01 06:00:00    -1
# 8 2019-01-01 07:00:00     0
# 9 2019-01-01 08:00:00     0
#10 2019-01-01 09:00:00     0
# … with 15 more rows

要包含该maxgap功能,我们可以用第一个减去最后Datetime一个,如果它大于某个值replace,则使用NA,例如下面我已经完成了 10 小时的持续时间。

testdf %>%
   group_by(group = lag(cumsum(!is.na(Value)), default = 1)) %>%
   mutate(Value = last(Value)/n(), 
          Value = replace(Value, as.integer(difftime(DateTime[max(n() - 1, 1)],
                  first(DateTime), units = "hours")) > 10, NA))

推荐阅读