Соедините два кадра данных к ближайшей дате, не переходя в R - PullRequest
1 голос
/ 12 октября 2019

У меня есть два кадра данных разной длины. Оба фрейма данных содержат даты. Я хотел бы присоединиться к ближайшему столбцу даты, не переходя. Например, если «2019-01-05» является датой, а два варианта - «2019-01-06» и «2019-01-02», он объединяется с «2019-01-02». Я попытался использовать roll "inf" из пакета data.table, но не получил желаемого результата. Вот 2 фрейма данных игрушек, к которым я хочу присоединиться по дате.

Я также хотел бы сгруппировать объединение по столбцу тикера. В Tidyverse код будет похож на:

df1 %>% group_by(ticker) %>% inner_join(df2, by = "Date") #but choose the closest date without going over.


df1 = data.frame(ticker = c("AAPL", "AAPL", "MSFT", "MSFT"), date = c("2019-01-06", "2019-02-06", "2019-01-06", "2019-05-02"))

df2 = data.frame(ticker = c("AAPL", "AAPL", "AAPL", "MSFT", "MSFT", "MSFT"), date = c("2019-01-03", "2019-01-07" , "2019-02-06", "2019-01-05", "2019-01-07", "2019-05-02"), randomVar = rnorm(6))

print(df1)
 ticker       date
1   AAPL 2019-01-06
2   AAPL 2019-02-06
3   MSFT 2019-01-06
4   MSFT 2019-05-02


print(df2)
 ticker       date  randomVar
1   AAPL 2019-01-03 -0.5321493
2   AAPL 2019-01-07 -0.7909461
3   AAPL 2019-02-06  0.2121993
4   MSFT 2019-01-05  1.2336315
5   MSFT 2019-01-07 -0.2729354
6   MSFT 2019-05-02 -0.5349596

Я хотел бы создать df3, который является объединением между df1 и df2. Столбец ключа даты должен быть только столбцом даты df1.

В этом случае наш новый df3 должен выглядеть точно так же.

 print(df3)

 ticker       date   randomVar
1   AAPL 2019-01-06  -0.5321493
2   AAPL 2019-02-06   0.2121993
3   MSFT 2019-01-06   1.2336315
4   MSFT 2019-05-02   -0.5349596

Ответы [ 2 ]

6 голосов
/ 12 октября 2019

Уже есть принятый ответ, но поскольку присутствует тег data.table, вот решение data.table:

#convert sample data to data.table
setDT(df1)
setDT(df2)
#convert dates to 'real' dates
df1[, date := as.IDate(date) ]
df2[, date := as.IDate(date) ]
#update df1 by reference with a rolling join
df1[, randomVar := df2[ df1, x.randomVar, on = .(ticker, date), roll = Inf ] ]

#    ticker       date  randomVar
# 1:   AAPL 2019-01-06 -0.5321493
# 2:   AAPL 2019-02-06  0.2121993
# 3:   MSFT 2019-01-06  1.2336315
# 4:   MSFT 2019-05-02 -0.5349596
4 голосов
/ 12 октября 2019

Это может быть сделано в SQL с бэкэндом SQLite по умолчанию с использованием левого соединения на тикере и на дате df2, которая меньше или равна дате df1, а затем группируется по df1 и берет максимальную дату из df2 из тех, которые присоединяются к df1.

library(sqldf)
sqldf("select df1.*, max(df2.date), df2.randomVar from df1 
  left join df2 on df1.ticker = df2.ticker and df1.date >= df2.date
  group by df1.rowid
  order by df1.rowid")[-3]

подача:

  ticker       date  randomVar
1   AAPL 2019-01-06 -0.5321493
2   AAPL 2019-02-06  0.2121993
3   MSFT 2019-01-06  1.2336315
4   MSFT 2019-05-02 -0.5349596

Примечание

Входные данные в воспроизводимой форме:

Lines1 <- "ticker       date
1   AAPL 2019-01-06
2   AAPL 2019-02-06
3   MSFT 2019-01-06
4   MSFT 2019-05-02"


Lines2 <- "ticker       date  randomVar
1   AAPL 2019-01-03 -0.5321493
2   AAPL 2019-01-07 -0.7909461
3   AAPL 2019-02-06  0.2121993
4   MSFT 2019-01-05  1.2336315
5   MSFT 2019-01-07 -0.2729354
6   MSFT 2019-05-02 -0.5349596"

df1 <- read.table(text = Lines1, as.is = TRUE)
df2 <- read.table(text = Lines2, as.is = TRUE)
...