Соедините два фрейма данных вместе и используйте самый последний результат как добавленные строки - PullRequest
1 голос
/ 10 июля 2019

Я пытаюсь получить вывод 'Final.Data', показанный ниже.

Мы начинаем с Базовых данных, и я хочу добавить «Add.Data», но присоединиться к «Персоне» и вернуть самый последний результат до ссылки (дата).

Я ищу решения dplyr, data.table или sql в г.

Затем я хочу иметь возможность воспроизвести это для тысяч записей, поэтому ищу разумное эффективное решение.

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 ]

4 голосов
/ 10 июля 2019

Быстрое соединение до ближайшей даты должно работать довольно быстро.

#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
3 голосов
/ 10 июля 2019

Подход, использующий 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 голосов
/ 10 июля 2019

Другое 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
1 голос
/ 10 июля 2019

Мы можем сделать inner_join и затем сгруппировать по «Person», slice строке с max «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]
0 голосов
/ 10 июля 2019

Влево присоедините Reference.Data к Add.Data, присоединяясь к Person и к Order.Date, находящемуся в или до Date. Сгруппируйте их по исходным Reference.Data строкам и возьмите максимум Order.Date из них. Это работает так, что строка Add.Data, используемая для каждой строки Reference.Data, будет строкой с максимальным значением Order.Date, поэтому будет отображаться правильный Order.

Обратите внимание, что точка - это оператор 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

Я не проверял, насколько это быстро (добавление индексов может ускорить его, если это необходимо), но эффективность с несколькими тысячами строк вряд ли так важна, как читабельность.

...