使用dplyr填充缺少的序列值

时间:2015-07-16 22:08:17

标签: r dplyr

我的数据框缺少" SNAP_ID"的值。我想根据前一个非缺失值(lag()?)的序列用浮点值填充缺失值。如果可能的话,我真的想用dplyr实现这个目的。

假设:

  1. 根据数据集的最小值和最大值之间缺少的天数生成缺失日期的第一行或最后一行永远不会丢失数据
  2. 数据集中可能存在多个空白
  3. 当前数据:

                      end SNAP_ID
    1 2015-06-26 12:59:00     365
    2 2015-06-26 13:59:00     366
    3 2015-06-27 00:01:00      NA
    4 2015-06-27 23:00:00      NA
    5 2015-06-28 00:01:00      NA
    6 2015-06-28 23:00:00      NA
    7 2015-06-29 09:00:00     367
    8 2015-06-29 09:59:00     368
    

    我想要实现的目标:

                      end SNAP_ID
    1 2015-06-26 12:59:00     365.0
    2 2015-06-26 13:59:00     366.0
    3 2015-06-27 00:01:00     366.1
    4 2015-06-27 23:00:00     366.2
    5 2015-06-28 00:01:00     366.3
    6 2015-06-28 23:00:00     366.4
    7 2015-06-29 09:00:00     367.0
    8 2015-06-29 09:59:00     368.0
    

    作为数据框:

    df <- structure(list(end = structure(c(1435323540, 1435327140, 1435363260, 
        1435446000, 1435449660, 1435532400, 1435568400, 1435571940), tzone = "UTC", class = c("POSIXct", 
        "POSIXt")), SNAP_ID = c(365, 366, NA, NA, NA, NA, 367, 368)), .Names = c("end", 
        "SNAP_ID"), row.names = c(NA, -8L), class = "data.frame")
    

    这是我尝试实现这一目标,但它只适用于第一个缺失的值:

    df %>% 
      arrange(end) %>%
      mutate(SNAP_ID=ifelse(is.na(SNAP_ID),lag(SNAP_ID)+0.1,SNAP_ID))
    
                      end SNAP_ID
    1 2015-06-26 12:59:00   365.0
    2 2015-06-26 13:59:00   366.0
    3 2015-06-27 00:01:00   366.1
    4 2015-06-27 23:00:00      NA
    5 2015-06-28 00:01:00      NA
    6 2015-06-28 23:00:00      NA
    7 2015-06-29 09:00:00   367.0
    8 2015-06-29 09:59:00   368.0
    

    以下@ mathematical.coffee的优秀答案:

    df %>% 
      arrange(end) %>%
      group_by(tmp=cumsum(!is.na(SNAP_ID))) %>%
      mutate(SNAP_ID=SNAP_ID[1] + 0.1*(0:(length(SNAP_ID)-1))) %>%
      ungroup() %>%
      select(-tmp)
    

1 个答案:

答案 0 :(得分:5)

编辑:新版本适用于任意数量的NA运行。 这个也不需要zoo

首先,请注意tmp=cumsum(!is.na(SNAP_ID))SNAP_ID个相同tmp组成的这类组合包含一个非NA值,后跟一系列NA值。

然后按此变量分组,只需将.1添加到第一个SNAP_ID以填写NA:

df %>% 
  arrange(end) %>%
  group_by(tmp=cumsum(!is.na(SNAP_ID))) %>%
  mutate(SNAP_ID=SNAP_ID[1] + 0.1*(0:(length(SNAP_ID)-1)))

                  end SNAP_ID tmp
1 2015-06-26 12:59:00   365.0   1
2 2015-06-26 13:59:00   366.0   2
3 2015-06-27 00:01:00   366.1   2
4 2015-06-27 23:00:00   366.2   2
5 2015-06-28 00:01:00   366.3   2
6 2015-06-28 23:00:00   366.4   2
7 2015-06-29 09:00:00   367.0   3
8 2015-06-29 09:59:00   368.0   4

然后您可以在之后删除tmp列(将%>% select(-tmp)添加到结尾)。

编辑:这是旧版本,不适用于NA的后续运行。

如果您的目标是使用之前的值+ 0.1填充每个NA,则可以使用zoo的{​​{1}}(使用之前的值填充每个na.locf),以及NA添加额外的0.1。

cumsum(is.na(SNAP_ID))*0.1