R - 使用键加入数据帧,然后使用近似日期

时间:2018-04-18 18:20:29

标签: r join dplyr lubridate

问题

我正在尝试使用3个ID列合并两个数据帧(或者1列,如果我将3个粘贴在一起),其中一个是日期时间变量,并且可以在两个数据帧之间变化最多1秒。

背景

我从具有交易记录的库中提取了两个数据帧。出于某种原因,结账​​和签到是单独记录的,没有唯一的交易ID"匹配他们。我想要匹配它们。 "退房" dataframe具有已签出的每个项目的记录,包括截止日期(应返回该项目时)。 "办理登机手续" dataframe包含已签入的每个项目的记录,包括截止日期。不幸的是,由于两个原因,我很难将这些数据帧合并在一起:

  1. 没有与表匹配的唯一交易ID。 (为什么?我不知道。)
  2. " due_date"对于同一交易,每笔交易的字段最多可以变化一秒。
  3. due_date的变化似乎是随机发生的,因此无法确定两个due_dates相等或相差1秒的记录。否则,我可以减去(或添加)一秒钟以使它们相等。

    数据

    以下是我正在使用的数据示例:

    library(dplyr)
    library(lubridate)
    
    check_in <- tribble(
      ~ patron_id, ~item_id, ~checked_in, ~due_date,
        "A", "Z", "2018-04-16 07:00:00", "2018-04-16 08:00:00",
        "A", "Y", "2018-04-17 07:30:01", "2018-04-17 08:30:01",
        "B", "X", "2018-04-17 07:00:01", "2018-04-17 08:00:01",
        "B", "Z", "2018-04-17 08:00:01", "2018-04-17 09:00:01",
        "B", "Z", "2018-04-09 09:00:01", "2018-04-09 10:00:01",
        "C", "V", "2018-04-09 09:00:01", "2018-04-09 10:00:01",
        "C", "X", "2018-04-09 09:00:01", "2018-04-09 10:00:01")
    
    check_out <- tribble(
      ~ patron_id, ~item_id, ~checked_out, ~due_date,
        "A", "Z", "2018-04-16 06:00:00", "2018-04-16 08:00:01",
        "A", "Y", "2018-04-17 06:30:01", "2018-04-17 08:30:00",
        "B", "X", "2018-04-17 06:00:01", "2018-04-17 08:00:00",
        "B", "Z", "2018-04-17 07:00:01", "2018-04-17 09:00:00",
        "B", "Z", "2018-04-09 08:00:01", "2018-04-09 10:00:01",
        "C", "V", "2018-04-09 08:00:01", "2018-04-09 10:00:01",
        "C", "X", "2018-04-09 08:00:01", "2018-04-09 10:00:00")
    
    check_in$due_date <- ymd_hms(check_in$due_date)
    check_in$checked_in <- ymd_hms(check_in$checked_in)
    
    check_out$due_date <- ymd_hms(check_out$due_date)
    check_out$checked_out <- ymd_hms(check_out$checked_out)
    

    赞助人ID是签出图书的人的唯一ID。商品ID是商品的唯一ID。签出是签出本书的时间。签入是指书籍签入时。截止日期是书籍到期的时间。

    对于此样本数据,我将所有截止日期等于结账日期后的2小时。我还在办理退房日期后的1小时内办理了入住日期。

    所需输出

    我想采取&#34; checked_in&#34;来自check_in数据帧的变量,并将其与check_out数据帧中的相应事务相匹配。输出将是这样的,但可能有某种生成的事务ID:

    desired_output <- tribble(
      ~patron_id, ~item_id, ~checked_out, ~checked_in, ~due_date,
        "A", "Z", "2018-04-16 06:00:00", "2018-04-16 07:00:00", "2018-04-16 08:00:01",
        "A", "Y", "2018-04-17 06:30:01", "2018-04-17 07:30:01", "2018-04-17 08:30:00",
        "B", "X", "2018-04-17 06:00:01", "2018-04-17 07:00:01", "2018-04-17 08:00:00",
        "B", "Z", "2018-04-17 07:00:01", "2018-04-17 08:00:01", "2018-04-17 09:00:00",
        "B", "Z", "2018-04-09 08:00:01", "2018-04-09 09:00:01", "2018-04-09 10:00:01",
        "C", "V", "2018-04-09 08:00:01", "2018-04-09 09:00:01", "2018-04-09 10:00:01",
        "C", "X", "2018-04-09 08:00:01", "2018-04-09 09:00:01", "2018-04-09 10:00:00")
    

    我尝试了什么

    ATTEMPT#1:

    我已尝试有条件地合并,如this帖子中所述,并进行了以下修改:

    check_out <- check_out %>%
                 mutate(transaction_id = paste(patron_id,"-",item_id,sep=""))
    check_in <- check_in %>%
                  mutate(transaction_id = paste(patron_id,"-",item_id,sep=""))
    
    output <- merge(check_out, check_in, by="transaction_id")[abs(difftime(check_out$due_date, check_in$due_date, units = "secs"))<=1,]
    

    但是这种方法并没有处理相同的交易ID(显然),并创造了比实际更多的记录。

    ATTEMPT#2:

    恢复原始数据框,我尝试了this post中的解决方案,并进行了以下修改:

    output <- cbind(check_out, check_in[ 
                      sapply(check_out$due_date, 
                        function(x) which.min(abs(difftime(x, check_in$due_date)))), ])
    

    但是这种方法不考虑&#34;事务ID&#34;,或者更确切地说,我用来创建某种唯一ID的两个关键变量。因此,输出错误。

    其他不成功的尝试:

    1. this article中提到的模糊连接。 (以及提到的其他基于R的解决方案。)
    2. response,使用过滤。
    3. 不幸的是,我无法让这些工作。我对这些方法的工作原理并没有信心,也没有产生我想要的东西。很可能是用户错误,因为似乎其他人能够得到类似的东西。

      感谢

      先谢谢你,如果你能帮助我的话。我倾向于使用Tidyverse提供的工具,但我愿意使用其他工具和方法。我试图确保在搜索其他解决方案时做了尽职调查,但如果您发现我错过了重要帖子,请将此标记为重复,并按照我的方式发送该帖子。

      如果我能提供任何其他信息或澄清上述任何细节,请告诉我。

1 个答案:

答案 0 :(得分:1)

会这样:

inner_join(check_in, check_out, by = c("patron_id", "item_id")) %>%
  filter(abs(difftime(due_date.y, due_date.x, units= "secs"))<=as.difftime(1, format = "%S", units = "secs"))

说明:简单连接+过滤时间差<= 1秒

的行