首页 > 解决方案 > 匹配 R 中数据框列表中的日期

问题描述

我有一个包含 100 多个时间序列数据框的列表,其中my.list包含每个产品在其自己的数据框中的每日观察结果。有些值是 NA,没有任何日期记录。我想更新此列表中的每个数据框以显示日期以及NA是否在此日期没有记录。

日期:

start = as.Date('2016/04/08')
full <- seq(start, by='1 days', length=10)

采样时间序列数据:

d1 <- data.frame(Date = seq(start, by ='2 days',length=5), Sales = c(5,10,15,20,25))
d2 <- data.frame(Date = seq(start, by= '1 day', length=10),Sales = c(1, 2, 3,4,5,6,7,8,9,10))
my.list <- list(d1, d2)

我想将所有full日期值合并到每个数据框中,如果不存在匹配项,sales则为 NA:

   my.list

[[d1]]
Date    Sales
2016-04-08    5
2016-04-09    NA
2016-04-10    10
2016-04-11    NA
2016-04-12    15
2016-04-13    NA
2016-04-14    20
2016-04-15    NA
2016-04-16    25
2016-04-17    NA


[[d2]]
Date    Sales
2016-04-08    1
2016-04-09    2
2016-04-10    3
2016-04-11    4
2016-04-12    5
2016-04-13    6
2016-04-14    7
2016-04-15    8
2016-04-16    9
2016-04-17    10

标签: rdatetime-seriesmatch

解决方案


如果我理解正确,OP希望更新每个数据帧my.list以包含日期向量中给定的每个日期的一行full

碱基R

在基础 R 中,merge()可以使用Hack-R已经提到的。但是,下面的答案将此扩展为适用于列表中的所有数据框:

# creat dataframe from vector of full dates
full.df <- data.frame(Date = full)
# apply merge on each dataframe in the list
lapply(my.list, merge, y = full.df, all.y = TRUE)
[[1]]
         Date Sales
1  2016-04-08     5
2  2016-04-09    NA
3  2016-04-10    10
4  2016-04-11    NA
5  2016-04-12    15
6  2016-04-13    NA
7  2016-04-14    20
8  2016-04-15    NA
9  2016-04-16    25
10 2016-04-17    NA

[[2]]
         Date Sales
1  2016-04-08     1
2  2016-04-09     2
3  2016-04-10     3
4  2016-04-11     4
5  2016-04-12     5
6  2016-04-13     6
7  2016-04-14     7
8  2016-04-15     8
9  2016-04-16     9
10 2016-04-17    10

警告

答案假设涵盖列表中所有数据帧full的整体范围。Date

为了避免任何意外,Date可以从以下可用数据中检索的整体范围my.list

overall_date_range <- Reduce(range, lapply(my.list, function(x) range(x$Date)))
full <- seq(overall_date_range[1], overall_date_range[2], by = "1 days")

使用rbindlist()

或者,可以将结构相同的数据帧列表存储在一个大数据帧中。附加属性指示每行属于哪个产品。同质结构简化了后续操作。

下面的代码使用包中的rbindlist()函数data.table来创建一个大的data.table. CJ()( cross join ) 创建日期和产品 ID 的所有组合,然后合并/连接以填充缺失的日期:

library(data.table)
all_products <- rbindlist(my.list, idcol = "product.id")[
  CJ(product.id = unique(product.id), Date = seq(min(Date), max(Date), by = "1 day")), 
  on = .(Date, product.id)]
all_products
    product.id       Date Sales
 1:          1 2016-04-08     5
 2:          1 2016-04-09    NA
 3:          1 2016-04-10    10
 4:          1 2016-04-11    NA
 5:          1 2016-04-12    15
 6:          1 2016-04-13    NA
 7:          1 2016-04-14    20
 8:          1 2016-04-15    NA
 9:          1 2016-04-16    25
10:          1 2016-04-17    NA
11:          2 2016-04-08     1
12:          2 2016-04-09     2
13:          2 2016-04-10     3
14:          2 2016-04-11     4
15:          2 2016-04-12     5
16:          2 2016-04-13     6
17:          2 2016-04-14     7
18:          2 2016-04-15     8
19:          2 2016-04-16     9
20:          2 2016-04-17    10

后续操作可以按 分组product.id,例如,确定每个产品的有效销售数据的数量:

all_products[!is.na(Sales), .(valid.sales.data = .N), by = product.id]
   product.id valid.sales.data
1:          1                5
2:          2               10

或者,每种产品的总销售额:

all_products[, .(total.sales = sum(Sales, na.rm = TRUE)), by = product.id]
   product.id total.sales
1:          1          75
2:          2          55

如果出于某种原因需要,可以通过以下方式将结果转换回列表

split(all_products, by = "product.id")

推荐阅读