【问题标题】:Adding missing dates to dataframe将缺失的日期添加到数据框中
【发布时间】:2014-01-08 22:43:01
【问题描述】:

我有一个如下所示的数据框:

    times                      values
1   2013-07-06 20:00:00        0.02
2   2013-07-07 20:00:00        0.03
3   2013-07-09 20:00:00        0.13
4   2013-07-10 20:00:00        0.12
5   2013-07-11 20:00:00        0.03
6   2013-07-14 20:00:00        0.06
7   2013-07-15 20:00:00        0.08
8   2013-07-16 20:00:00        0.07
9   2013-07-17 20:00:00        0.08

数据中缺少一些日期,我想插入它们并将前一天的值结转到这些新行中,即获取:

    times                      values
1   2013-07-06 20:00:00        0.02
2   2013-07-07 20:00:00        0.03
3   2013-07-08 20:00:00        0.03
4   2013-07-09 20:00:00        0.13
5   2013-07-10 20:00:00        0.12
6   2013-07-11 20:00:00        0.03
7   2013-07-12 20:00:00        0.03
8   2013-07-13 20:00:00        0.03
9   2013-07-14 20:00:00        0.06
10  2013-07-15 20:00:00        0.08
11  2013-07-16 20:00:00        0.07
12  2013-07-17 20:00:00        0.08
...

我一直在尝试使用所有日期的向量:

dates <- as.Date(1:length(df),origin = df$times[1])

我被卡住了,如果没有一个可怕的 for 循环,我找不到解决方法,我在其中迷路了...... 谢谢你的帮助

【问题讨论】:

  • 请问您为什么要结转前一天的值?它可能应该是 NA,否则你会用“假”数据填充表格,这在许多情况下可能是个问题。

标签: r date dataframe rows


【解决方案1】:

一些测试数据(我用的是Date,你的好像是不同的类型,但这不影响算法):

data = data.frame(dates = as.Date(c("2011-12-15", "2011-12-17", "2011-12-19")), 
                  values = as.double(1:3))

# Generate **all** timestamps at which you want to have your result. 
# I use `seq`, but you may use any other method of generating those timestamps. 

alldates = seq(min(data$dates), max(data$dates), 1)

# Filter out timestamps that are already present in your `data.frame`:
# Construct a `data.frame` to append with missing values:
dates0 = alldates[!(alldates %in% data$dates)]
data0 = data.frame(dates = dates0, values = NA_real_)

# Append this `data.frame` and resort in time:
data = rbind(data, data0)
data = data[order(data$dates),]

# forward fill the values 
# I would recommend to move this code into a separate `ffill` function: 
# proved to be very useful in general):
current = NA_real_
data$values = sapply(data$values, function(x) { 
           current <<- ifelse(is.na(x), current, x); current })

【讨论】:

    【解决方案2】:
    library(zoo)
    g <- data.frame(dates=seq(min(data$dates),max(data$dates),1))
    na.locf(merge(g,data,by="dates",all.x=TRUE))
    

    或完全使用动物园:

    z <- read.zoo(data)
    gz <- zoo(, seq(min(time(z)), max(time(z)), "day"))  # time grid in zoo
    na.locf(merge(z, gz))
    

    【讨论】:

      【解决方案3】:

      假设times 列已经属于POSIXct 类,则使用tidyrcompletefill

      library(tidyr)
      df %>%
        complete(times = seq(min(times), max(times), by = 'day')) %>%
        fill(values)
      
      # A tibble: 12 x 2
      #   times               values
      #   <dttm>               <dbl>
      # 1 2013-07-06 20:00:00   0.02
      # 2 2013-07-07 20:00:00   0.03
      # 3 2013-07-08 20:00:00   0.03
      # 4 2013-07-09 20:00:00   0.13
      # 5 2013-07-10 20:00:00   0.12
      # 6 2013-07-11 20:00:00   0.03
      # 7 2013-07-12 20:00:00   0.03
      # 8 2013-07-13 20:00:00   0.03
      # 9 2013-07-14 20:00:00   0.06
      #10 2013-07-15 20:00:00   0.08
      #11 2013-07-16 20:00:00   0.07
      #12 2013-07-17 20:00:00   0.08
      

      数据

      df <- structure(list(times = structure(c(1373140800, 1373227200, 1373400000, 
      1373486400, 1373572800, 1373832000, 1373918400, 1374004800, 1374091200
      ), class = c("POSIXct", "POSIXt"), tzone = "UTC"), values = c(0.02, 
      0.03, 0.13, 0.12, 0.03, 0.06, 0.08, 0.07, 0.08)), row.names = c(NA, 
      -9L), class = "data.frame")
      

      【讨论】:

        【解决方案4】:
        df2 <- data.frame(times=seq(min(df$times), max(df$times), by="day"))
        df3 <- merge(x=df2, y=df, by="times", all.x=T)
        idx <- which(is.na(df3$values))
        for (id in idx) 
          df3$values[id] <- df3$values[id-1]
        df3
        #                  times values
        # 1  2013-07-06 20:00:00   0.02
        # 2  2013-07-07 20:00:00   0.03
        # 3  2013-07-08 20:00:00   0.03
        # 4  2013-07-09 20:00:00   0.13
        # 5  2013-07-10 20:00:00   0.12
        # 6  2013-07-11 20:00:00   0.03
        # 7  2013-07-12 20:00:00   0.03
        # 8  2013-07-13 20:00:00   0.03
        # 9  2013-07-14 20:00:00   0.06
        # 10 2013-07-15 20:00:00   0.08
        # 11 2013-07-16 20:00:00   0.07
        # 12 2013-07-17 20:00:00   0.08
        

        【讨论】:

        • merge很好!对于连续 NA 的情况和前导 NA 的情况,循环是错误的。在大型数据集上循环也会非常慢(请参阅我的解决方案)
        • 嘿@OlegS。 , 感谢您的反馈。同意,您的解决方案要快得多-nice1。但是我在这里看不到for 循环的逻辑问题(?)。我把这归咎于拉弗格。
        • 对不起,我的错——你是对的:通常循环会很好,尽管速度很慢,但前导 NA 的问题仍然存在(部分),即如果第一个值为 NA,那么第一个 @ 987654324@ 为 1,索引 id-1 对于基于 1 的 R 向量无效。好吧,我猜 R 在这种情况下会返回 NA,但我认为以这种方式编程是不好的做法。
        • 第一个值总是min(data$dates),所以这也没有问题。循环可以工作,但是太慢了。
        【解决方案5】:

        你可以试试这个:

           setkey(NADayWiseOrders, date)
           all_dates <- seq(from = as.Date("2013-01-01"), 
                       to = as.Date("2013-01-07"), 
                       by = "days")
        
          NADayWiseOrders[J(all_dates), roll=Inf]
             date orders  amount guests
          1: 2013-01-01     50 2272.55    149
          2: 2013-01-02      3   64.04      4
          3: 2013-01-03      3   64.04      4
          4: 2013-01-04      1   18.81      0
          5: 2013-01-05      2   77.62      0
          6: 2013-01-06      2   77.62      0
          7: 2013-01-07      2   35.82      2
        

        【讨论】:

          猜你喜欢
          • 2013-10-19
          • 2021-04-06
          • 2021-08-11
          • 1970-01-01
          • 2023-01-22
          • 2013-04-29
          • 2018-03-02
          • 2017-12-02
          • 2022-01-25
          相关资源
          最近更新 更多