输入数据:
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
被nondecreasingly和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
+1对于'cut'。另外,我想,'findInterval'将起到类似的作用。 – gagolews
@gagolews'findInterval'使用左侧关闭的时间间隔。 'cut'给出了一个选择(右边是默认值)。 –
'rightmost.closed'? – gagolews