我有两个不同长度的数据帧。两个数据框都包含日期。我想内部加入最接近的日期列而不跳过。例如,如果“2019-01-05”是日期,两个选择是“2019-01-06”和“2019-01-02”,则它与“2019-01-02”连接。我尝试使用 data.table 包中的 roll“inf”,但没有得到所需的结果。这是我想按日期加入的 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
这可以在 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)
已经有一个接受的答案,但由于存在
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
随着 dplyr 1.1.0 获得
closest
功能,现在超级简单
library(dplyr)
#>
df1 %>%
left_join(df2,
by = join_by(ticker == ticker,
closest(date >= date)))
#> ticker date.x date.y randomVar
#> 1 AAPL 2019-01-06 2019-01-03 -0.5321493
#> 2 AAPL 2019-02-06 2019-02-06 0.2121993
#> 3 MSFT 2019-01-06 2019-01-05 1.2336315
#> 4 MSFT 2019-05-02 2019-05-02 -0.5349596
创建于 2023-04-07,使用 reprex v2.0.2