查找一个向量中小于另一个向量中的元素的元素数

时间:2014-04-08 16:18:59

标签: r sorting vector time-complexity ranking

假设我们有几个载体

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

3 个答案:

答案 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