【问题标题】:Fill missing sequence values with dplyr用 dplyr 填充缺失的序列值
【发布时间】:2015-10-06 13:24:26
【问题描述】:

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

假设:

  1. 永远不会丢失数据作为第一行或最后一行我根据数据集的最小值和最大值之间的缺失天数生成缺失日期
  2. 数据集中可能存在多个缺口

当前数据:

                  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)

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

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

    首先,请注意tmp=cumsum(!is.na(SNAP_ID))SNAP_IDs 分组,这些相同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 列(在末尾添加%&gt;% select(-tmp))。


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

    如果您的目标是用之前的值 + 0.1 填充每个 NA,您可以使用 zoona.locf(用之前的值填充每个 NA)以及 cumsum(is.na(SNAP_ID))*0.1 来添加额外0.1。

    library(zoo)
    df %>% 
      arrange(end) %>%
      mutate(SNAP_ID=ifelse(is.na(SNAP_ID),
                           na.locf(SNAP_ID) + cumsum(is.na(SNAP_ID))*0.1,
                           SNAP_ID))
    

    【讨论】:

    • 感谢您的出色回答!唯一的小修正是您需要在选择(-tmp)之前取消分组()。 ungroup() 有时让我发疯。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-09
    • 1970-01-01
    • 2013-05-15
    • 1970-01-01
    • 2012-10-25
    相关资源
    最近更新 更多