【问题标题】:R: Import values from one dataframe to another by matching datesR:通过匹配日期将值从一个数据帧导入到另一个数据帧
【发布时间】:2020-09-20 02:25:13
【问题描述】:

假设我有 df1:

Start_Date    End_Date     Value
2001-01-01    2001-12-31   1
2002-01-01    2002-12-31   2
2003-01-01    2003-12-31   3
2004-01-01    2004-12-31   4
2005-01-01    2005-12-31   5 

&df2:

DateTime      Gain   People
2003-01-01    3      3
2003-05-09    5      4
2004-12-31    1      2
2005-01-31    -2     2
2005-08-13    9      7
2006-09-10    6      8
2007-10-03    7      5

我想做的是通过检查 df2 中的哪个 DateTime 位于 df1 中的 Start_Date 和 End_Date 之间,将值从 df1 导入 df2。如果日期不属于 df1 中的任何时期,则返回值 0。期望结果的视图:

DateTime      Gain   People   Value
2003-01-01    3      3        3
2003-05-09    5      4        3
2004-12-31    1      2        4
2005-01-31    -2     2        5
2005-08-13    9      7        5
2006-09-10    6      8        0
2007-10-03    7      5        0

请指教

【问题讨论】:

  • 使用data.table:library(data.table) ; setDT(df2)[setDT(df), Value := i.Value, on = .(DateTime >= Start_Date, DateTime <= End_Date)]

标签: r dataframe datetime dplyr subset


【解决方案1】:

潜在的挑战是加入不平等条件。这些在 sql 中很简单,但在 R 中不是,因为 dplyr 仅在相等时加入。 Here 是 S.O. 上主要答案的链接。

我发现的最佳方法是进行更一般的连接,然后过滤不等式。

df1 = df1 %>% mutate(join_id = 1)
df2 = df2 %>% mutate(join_id = 1)

output = left_join(df2, df1, by = 'join_id') %>%
  filter(Start_Date <= DateTime,
         DateTime <= End_Date) %>%
  select(DateTime, Gain, People, Value) %>%
  mutate(Value = ifelse(is.na(Value), 0, Value)

解释:

  • 由于您的数据框没有现有的 ID 列,我们首先创建一个。如果您想加入一些等式约束和一些不等式约束,这是不必要的。
  • 我们使用(更)更一般的连接,然后使用不等式约束过滤器。
  • ifelse(is.na(... 用于替换缺失值。

在某些情况下,这种更通用的连接会产生性能问题。但是由于 R 默认使用惰性求值,如果您在连接后立即进行过滤,那么 R 应该将两个语句作为同一连接的一部分运行并避免任何性能问题。

【讨论】:

  • R 中有一些包可以像您链接的帖子中的第二个答案一样进行非 equi 连接
【解决方案2】:

由于某种原因,我之前的答案被版主删除了,这意味着我无法取消删除它 - 无论如何,答案在下面复制了一个从其中一个链接中获取的解决方案。

您可能希望使用左范围连接来执行此操作

Merge 2 dataframes if value within range

Join tables by date range

matching time a time in the interval between a start and end time

这三个 SO 帖子应该给你一个很好的起点

编辑:我认为使用 sqldf 是上面 3 个链接中最简单的(无论如何是最清晰的语法)。

library(sqldf)
library(lubridate)
df1 <- data.frame(Start_Date=c(ymd("2001-01-01"),
                               ymd("2002-01-01"),
                               ymd("2003-01-01"),
                               ymd("2004-01-01"),
                                ymd("2005-01-01")),
                    End_Date=c(ymd("2001-12-31"),
                               ymd("2002-12-31"),
                               ymd("2003-12-31"),
                               ymd("2004-12-31"),
                               ymd("2005-12-31")),
                    Value=c(1,2,3,4,5))

df2 <- data.frame(DateTime=c(ymd("2003-01-01"),
                             ymd("2003-05-09"),
                             ymd("2004-12-31"),
                             ymd("2005-01-31"),
                             ymd("2005-08-13"),
                             ymd("2006-09-10"),
                             ymd("2007-10-03")),
                  Gain=c(3,5,1,-2,9,6,7),
                  People=c(3,4,2,2,7,8,5))

sqldf("SELECT DateTime,Gain,People,COALESCE(Value,0) AS Value FROM df2
            LEFT JOIN df1
            ON df2.DateTime BETWEEN df1.Start_Date AND df1.End_Date")

Coalesce 将 NA(不匹配)值更改为 0。其余的很容易解释。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-24
    • 1970-01-01
    • 2023-03-25
    • 2021-04-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多