假设我们有几个载体
a <- c(1, 2, 2, 4, 7)
b <- c(1, 2, 3, 5, 7)
对于b[i]
中的每个元素b
,我想找到a
中小于b[i]
的元素数量,或等效,我想要知道c(b[i], a)
中b_i的等级。
我可以想到几种天真的方式,例如:执行以下任一length(b)
次:
min_rank(c(b[i], a))
sum(a < b[i])
如果length(a)
= length(b)
= N,其中N很大,那么最好的方法是什么?
修改
为了澄清,我想知道是否有一种计算效率更高的方法,即在这种情况下我能做的比二次时更好。
矢量化总是很酷;),谢谢@Henrik!
运行时间
a <- rpois(100000, 20)
b <- rpois(100000, 10)
system.time(
result1 <- sapply(b, function(x) sum(a < x))
)
# user system elapsed
# 71.15 0.00 71.16
sw <- proc.time()
bu <- sort(unique(b))
ab <- sort(c(a, bu))
ind <- match(bu, ab)
nbelow <- ind - 1:length(bu)
result2 <- sapply(b, function(x) nbelow[match(x, bu)])
proc.time() - sw
# user system elapsed
# 0.46 0.00 0.48
sw <- proc.time()
a1 <- sort(a)
result3 <- findInterval(b - sqrt(.Machine$double.eps), a1)
proc.time() - sw
# user system elapsed
# 0.00 0.00 0.03
identical(result1, result2) && identical(result2, result3)
# [1] TRUE
答案 0 :(得分:5)
假设a
的排序越来越弱,请使用findInterval
:
a <- sort(a)
## gives points less than or equal to b[i]
findInterval(b, a)
# [1] 1 3 3 4 5
## to do strictly less than, subtract a small bit from b
## uses .Machine$double.eps (the smallest distinguishable difference)
findInterval(b - sqrt(.Machine$double.eps), a)
# [1] 0 1 3 4 4
答案 1 :(得分:3)
如果你真的为大N优化了这个过程,那么你可能想要至少在b
中删除重复值,然后你可以排序和匹配:
bu <- sort(unique(b))
ab <- sort(c(a, bu))
ind <- match(bu, ab)
nbelow <- ind - 1:length(bu)
由于我们已将a和b值合并为ab,match
包含所有小于b的特定值以及所有b,因此这就是为什么我们删除最后一行b的累积计数。我怀疑对于大型集合来说这可能会更快 - 如果match
在内部针对排序列表进行优化,那应该是更快的,人们希望是这种情况。将nbelow
映射回您原来的b
答案 2 :(得分:2)
我并不认为这是“最好的方式”,但它是一种方式。 sapply
将(匿名)function
应用于b
的每个元素。
sapply(b, function(x) sum(a < x))
# [1] 0 1 3 4 4