输入数据:
d1 <- data.frame(x=c(4,6,7), y=c(10,20,30))
d2 <- data.frame(x=c(3,6,9), z=c(100,200,300))
您基本上希望将d1 扩展一个新列。所以让我们复制它。
d3 <- d1
接下来我假设d2$x 是非递减排序的,而max(d1$x) <= max(d2$x)。
d3$z <- sapply(d1$x, function(x) d2$z[which(x <= d2$x)[1]])
其内容为:对于d1$x 中的每个x,从d2$x 中获取不小于x 的最小值。
在这些假设下,上面也可以写成(&应该快一点):
d3$z <- sapply(d1$x, function(x) d2$z[which.max(x <= d2$x)])
结果我们得到:
d3
## x y z
## 1 4 10 200
## 2 6 20 200
## 3 7 30 300
EDIT1:受到@MatthewLundberg 的基于cut 的解决方案的启发,这是另一个使用findInterval 的解决方案:
d3$z <- d2$z[findInterval(d1$x, d2$x+1)+1]
EDIT2:(基准)
示例数据:
set.seed(123)
d1 <- data.frame(x=sort(sample(1:10000, 1000)), y=sort(sample(1:10000, 1000)))
d2 <- data.frame(x=sort(c(sample(1:10000, 999), 10000)), z=sort(sample(1:10000, 1000)))
结果:
microbenchmark::microbenchmark(
{d3 <- d1; d3$z <- d2$z[findInterval(d1$x, d2$x+1)+1] },
{d3 <- d1; d3$z <- sapply(d1$x, function(x) d2$z[which(x <= d2$x)[1]]) },
{d3 <- d1; d3$z <- sapply(d1$x, function(x) d2$z[which.max(x <= d2$x)]) },
{d1$x2 <- d2$x[as.numeric(cut(d1$x, c(-Inf, d2$x, Inf)))]; merge(d1, d2, by.x='x2', by.y='x')},
{d1a <- d1; setkey(setDT(d1a), x); d2a <- d2; setkey(setDT(d2a), x); d2a[d1a, roll=-Inf] }
)
## Unit: microseconds
## expr min lq median uq max neval
## findInterval 221.102 1357.558 1394.246 1429.767 17810.55 100
## which 66311.738 70619.518 85170.175 87674.762 220613.09 100
## which.max 69832.069 73225.755 83347.842 89549.326 118266.20 100
## cut 8095.411 8347.841 8498.486 8798.226 25531.58 100
## data.table 1668.998 1774.442 1878.028 1954.583 17974.10 100