匹配两个非常大的向量与容差(快速!但工作空间保留)

时间:2017-10-26 14:54:16

标签: r vector matching

考虑我有两个向量。一个是参考向量/列表,其包括所有感兴趣的值和一个可包含任何可能值的样本向量。现在我想在参考列表中找到我的样本的匹配,并且具有一定的容差,该容差不是固定的,并且依赖于向量内的比较值:

matches: abs(((referencelist - sample[i])/sample[i])*10^6)) < 0.5

舍入两个向量是没有选择的!

例如考虑:

referencelist <- read.table(header=TRUE, text="value  name
154.00312  A
154.07685  B
154.21452  C
154.49545  D
156.77310  E
156.83991  F
159.02992  G
159.65553  H
159.93843  I")

sample <- c(154.00315, 159.02991, 154.07688, 156.77312)

所以我得到了结果:

    name value      reference
1    A   154.00315  154.00312
2    G   159.02991  159.02992
3    B   154.07688  154.07685
4    E   156.77312  156.77310

我能做的就是使用例如外部函数如

myDist <- outer(referencelist, sample, FUN=function(x, y) abs(((x - y)/y)*10^6))
matches <- which(myDist < 0.5, arr.ind=TRUE)
data.frame(name = referencelist$name[matches[, 1]], value=sample[matches[, 2]])

或者我可以使用for()循环。

但我的特殊问题是,参考向量有大约1 * 10 ^ 12个条目,我的样本向量大约是1 * 10 ^ 7。因此,通过使用outer(),我可以轻松破坏所有工作空间限制,并使用for()或链式for()循环,这将需要数天/数周才能完成。

有没有人知道如何在R中快速完成此操作,仍然是精确的但是在消耗最多的计算机上工作。 64 GB RAM?

感谢您的帮助!

最好的嘘声

2 个答案:

答案 0 :(得分:4)

使用data.table(以及@ eddi&#39; s binary search的复制粘贴(也称为二分法,参见@John Coleman的评论)):

library(data.table)

dt <- as.data.table(referencelist)
setattr(dt, "sorted", "value")

tol <- 0.5
dt2 <- dt[J(sample), .(.I, ref = value, name), roll = "nearest", by = .EACHI]
dt2[, diff := abs(ref - value) / value * 1e6]
dt2[diff <= tol]

#       value I      ref name       diff
# 1: 154.0032 1 154.0031    A 0.19480121
# 2: 159.0299 7 159.0299    G 0.06288125
# 3: 154.0769 2 154.0769    B 0.19470799
# 4: 156.7731 5 156.7731    E 0.12757289

我没有对内存使用情况进行基准测试,也没有执行时间,但是data.table的声誉非常好。如果它对您不起作用,请说明,也许我会尝试对事物进行基准测试。

注意:我对data.table的使用非常幼稚。

以下使用findInterval的解决方案:https://stackoverflow.com/a/29552922/6197649,但我希望它的效果会更差(再次:需要基准测试)。

答案 1 :(得分:3)

您的比赛条件

abs(((referencelist - sample[i])/sample[i])*10^6)) < 0.5

可以重写为

sample[i] * (1 - eps) < referencelist < sample[i] * (1 + eps)

eps = 0.5E-6

使用此功能,我们可以使用非等连接在每个{{referencelist中找到所有匹配(不仅是最近的!) 1}}:

sample

再现预期结果:

library(data.table)
options(digits = 10)
eps <- 0.5E-6 # tol * 1E6
setDT(referencelist)[.(value = sample, 
                       lower = sample * (1 - eps), 
                       upper = sample * (1 + eps)), 
                     on = .(ref > lower, ref < upper), .(name, value, reference = x.ref)]

在回复OP's comment时,假设我们修改了 name value reference 1: A 154.00315 154.00312 2: G 159.02991 159.02992 3: B 154.07688 154.07685 4: E 156.77312 156.77310 referencelist2,那么这也会被抓住:

F = 154.00320
setDT(referencelist2)[.(value = sample, 
                       lower = sample * (1 - eps), 
                       upper = sample * (1 + eps)), 
                     on = .(ref > lower, ref < upper), .(name, value, reference = x.ref)]