将两个数据框连接在一起,并使用最新结果作为添加的行

时间:2019-07-10 07:01:48

标签: r dplyr data.table sqldf

我正在尝试实现如下所示的“ Final.Data”输出。

我们从参考数据开始,我想添加“ Add.Data”,但要加入“人”并返回参考(日期)之前的最新结果。

我正在r中寻找dplyr,data.table或sql解决方案。

然后,我希望能够复制1000个条目,因此寻求合理的有效解决方案。

library(tibble)
Reference.Data  <-  tibble(Person = "John",
                           Date = "2019-07-10")

Add.Data <- tibble(Person = "John",
                   Order.Date = c("2019-07-09","2019-07-08") ,
                   Order = 1:2)

Final.Data <- tibble(Person = "John",
                     Date = "2019-07-10",
                     Order.Date = "2019-07-09",
                     Order = 1)

5 个答案:

答案 0 :(得分:4)

到最近日期的最近加入应该很快。.

#data preparation:
# convert to data.tables, set dates as 'real' dates
DT1 <- setDT(Reference.Data)[, Date := as.IDate( Date )]
DT2 <- setDT(Add.Data)[, Order.Date := as.IDate( Order.Date )]
#set keys (this also orders the dates, convenient for the join later)
setkey(DT1, Person, Date)
setkey(DT2, Person, Order.Date)

#perform rolling update join on DT1 
DT1[ DT2, `:=`( Order.date = i.Order.Date, Order = i.Order), roll = -Inf][]

#    Person       Date Order.date Order
# 1:   John 2019-07-10 2019-07-09     1

答案 1 :(得分:3)

一种使用data.table非等额联接并直接在Reference.Data上进行引用更新的方法:

library(data.table)
setDT(Add.Data)
setDT(Reference.Data)
setorder(Add.Data, Person, Order.Date)
Reference.Data[, (names(Add.Data)) :=
    Add.Data[.SD, on=.(Person, Order.Date<Date), mult="last",
        mget(paste0("x.", names(Add.Data)))]
]

输出:

   Person       Date Order.Date Order
1:   John 2019-07-10 2019-07-09     1

答案 2 :(得分:2)

另一种data.table解决方案:

setDT(Add.Data)[, Order.Date := as.Date(Order.Date)]
setDT(Reference.Data)[, Date := as.Date(Date)]

Reference.Data[, c("Order.Date", "Order") := Add.Data[.SD, 
                                                      on = .(Person, Order.Date = Date), 
                                                      roll = TRUE, 
                                                      .(x.Order.Date, x.Order)]]
Reference.Data

#    Person       Date Order.Date Order
# 1:   John 2019-07-10 2019-07-09     1

答案 3 :(得分:1)

我们可以先进行inner_join,然后按'Person'分组,slicemax'Order.Date'所在的行

library(tidyverse)
inner_join(Add.Data, Reference.Data) %>%
    group_by(Person) %>% 
    slice(which.max(as.Date(Order.Date)))
# A tibble: 1 x 4
# Groups:   Person [1]
#  Person Order.Date Order Date      
#  <chr>  <chr>      <int> <chr>     
#1 John   2019-07-09     1 2019-07-10

或使用data.tabl#

library(data.table)
setDT(Add.Data)[as.data.table(Reference.Data), on = .(Person)][, 
          .SD[which.max(as.Date(Order.Date))], by = Person]

答案 4 :(得分:0)

Reference.DataAdd.Data上的Person相连,并在Order.Date或之前的Date处加入。按原始的Reference.Data行将其分组,并从中获取最大的Order.Date。它的工作方式是,用于Add.Data每行的Reference.Data行将是具有最大Order.Date的行,因此将显示正确的Order。 / p>

请注意,点是一个SQL运算符,而order是一个SQL关键字,因此我们必须在名称周围加上点号或在名称order(无论大小写)之间加上方括号。

library(sqldf)

sqldf("select r.*, max(a.[Order.Date]) as [Order.Date], a.[Order]
  from [Reference.Data] as r
  left join [Add.Data] as a on r.Person = a.Person and a.[Order.Date] <= r.Date
  group by r.rowid")

给予:

  Person       Date Order.Date Order
1   John 2019-07-10 2019-07-09     1

我还没有检查这有多快(添加索引可以根据需要加快速度),但是只有几千行的效率并没有可读性那么重要。