通过加入 R 的条件组
Conditional group by join in R
我是 R 的新手,对以下问题感到困惑。我有两个日期向量(向量不一定对齐,长度也不相同)。
我想为第一个向量中的每个日期查找第二个向量中的下一个日期。
vecA <- as.Date(c('1951-07-01', '1953-01-01', '1957-04-01', '1958-12-01',
'1963-06-01', '1965-05-01'))
vecB <- as.Date(c('1952-01-12', '1952-02-01', '1954-03-01', '1958-08-01',
'1959-03-01', '1964-03-01', '1966-05-01'))
在 SQL 中,我会写这样的东西,但我在 SO 中找不到关于如何在 R 中执行此操作的任何提示。
select vecA.Date, min(vecB.Date)
from vecA inner join vecB
on vecA.Date < vecB.Date
group by vecA.Date
输出应如下所示:
Start End
1951-07-01 1952-01-12
1953-01-01 1954-03-01
1957-04-01 1958-08-01
1958-12-01 1959-03-01
1963-06-01 1964-03-01
1965-05-01 1966-05-01
此代码将执行您所要求的,但不清楚您要完成什么,因此这可能不是最佳方法。本质上,这段代码首先对两个向量进行排序,以确保它们的顺序相同。然后,使用 for
循环,遍历 vecA
中的所有元素,并使用 x < vecB
找出 vecB
中哪些元素小于 x
。
包裹在which
中,return是向量中每个TRUE
元素的数字索引,然后在min
中给出最小的数字索引。然后将其用于将 vecB
子集化为 return 日期;它全部包含在 print
中,因此您可以看到循环的输出。
这可能不是最好的方法,但如果没有更多关于您的目标的背景信息,它至少应该让您入门。
> vecA <- vecA[order(vecA)]
> vecB <- vecB[order(vecB)]
> for(x in vecA) {print(vecB[min(which(x < vecB))])}
[1] "1952-01-12"
[1] "1954-03-01"
[1] "1958-08-01"
[1] "1959-03-01"
[1] "1964-03-01"
[1] "1966-05-01"
这是使用 data.table
滚动连接的可能解决方案
library(data.table)
dt1 <- as.data.table(vecA) ## convert to `data.table` object
dt2 <- as.data.table(vecB) ## convert to `data.table` object
setkey(dt2) # key in order to perform a binary join
res <- dt2[dt1, vecB, roll = -Inf, by = .EACHI] # run the inner join while selecting closest date
setnames(res, c("Start", "End"))
res
# Start End
# 1: 1951-07-01 1952-01-12
# 2: 1953-01-01 1954-03-01
# 3: 1957-04-01 1958-08-01
# 4: 1958-12-01 1959-03-01
# 5: 1963-06-01 1964-03-01
# 6: 1965-05-01 1966-05-01
或者,我们也可以这样做:
data.table(vecA=vecB, vecB, key="vecA")[dt1, roll=-Inf]
我是 R 的新手,对以下问题感到困惑。我有两个日期向量(向量不一定对齐,长度也不相同)。
我想为第一个向量中的每个日期查找第二个向量中的下一个日期。
vecA <- as.Date(c('1951-07-01', '1953-01-01', '1957-04-01', '1958-12-01',
'1963-06-01', '1965-05-01'))
vecB <- as.Date(c('1952-01-12', '1952-02-01', '1954-03-01', '1958-08-01',
'1959-03-01', '1964-03-01', '1966-05-01'))
在 SQL 中,我会写这样的东西,但我在 SO 中找不到关于如何在 R 中执行此操作的任何提示。
select vecA.Date, min(vecB.Date)
from vecA inner join vecB
on vecA.Date < vecB.Date
group by vecA.Date
输出应如下所示:
Start End
1951-07-01 1952-01-12
1953-01-01 1954-03-01
1957-04-01 1958-08-01
1958-12-01 1959-03-01
1963-06-01 1964-03-01
1965-05-01 1966-05-01
此代码将执行您所要求的,但不清楚您要完成什么,因此这可能不是最佳方法。本质上,这段代码首先对两个向量进行排序,以确保它们的顺序相同。然后,使用 for
循环,遍历 vecA
中的所有元素,并使用 x < vecB
找出 vecB
中哪些元素小于 x
。
包裹在which
中,return是向量中每个TRUE
元素的数字索引,然后在min
中给出最小的数字索引。然后将其用于将 vecB
子集化为 return 日期;它全部包含在 print
中,因此您可以看到循环的输出。
这可能不是最好的方法,但如果没有更多关于您的目标的背景信息,它至少应该让您入门。
> vecA <- vecA[order(vecA)]
> vecB <- vecB[order(vecB)]
> for(x in vecA) {print(vecB[min(which(x < vecB))])}
[1] "1952-01-12"
[1] "1954-03-01"
[1] "1958-08-01"
[1] "1959-03-01"
[1] "1964-03-01"
[1] "1966-05-01"
这是使用 data.table
滚动连接的可能解决方案
library(data.table)
dt1 <- as.data.table(vecA) ## convert to `data.table` object
dt2 <- as.data.table(vecB) ## convert to `data.table` object
setkey(dt2) # key in order to perform a binary join
res <- dt2[dt1, vecB, roll = -Inf, by = .EACHI] # run the inner join while selecting closest date
setnames(res, c("Start", "End"))
res
# Start End
# 1: 1951-07-01 1952-01-12
# 2: 1953-01-01 1954-03-01
# 3: 1957-04-01 1958-08-01
# 4: 1958-12-01 1959-03-01
# 5: 1963-06-01 1964-03-01
# 6: 1965-05-01 1966-05-01
或者,我们也可以这样做:
data.table(vecA=vecB, vecB, key="vecA")[dt1, roll=-Inf]