【问题标题】:How to find column index for top n values of a matrix efficiently?如何有效地查找矩阵的前 n 个值的列索引?
【发布时间】:2017-04-01 20:50:12
【问题描述】:

给定一个矩阵,比如 m,是否有任何直接的方法可以找到 m 的前 k 个值,然后准确地找到它们属于哪个列/行。我在 SO 上找不到任何内容,因此提出了这个问题。 我对上面的尝试是这样的:

set.seed(1729)
k=5 #top 5
m = matrix(round(runif(30),digits = 2),nr=10)
idx <- which(matrix(m %in% head(sort(m), k), nr = nrow(m)), arr.ind = TRUE)
print(m)
      [,1] [,2] [,3]
 [1,] 0.59 0.54 0.57
 [2,] 0.44 0.43 0.32
 [3,] 0.57 0.08 0.29
 [4,] 0.35 0.58 0.24
 [5,] 0.86 0.52 0.53
 [6,] 0.41 0.78 0.17
 [7,] 0.51 0.47 0.26
 [8,] 0.15 0.81 0.49
 [9,] 0.85 0.64 0.64
[10,] 1.00 0.78 0.95

print(idx)

        row col
[1,]   8   1
[2,]   3   2
[3,]   4   3
[4,]   6   3
[5,]   7   3

我不确定这是否有效,因为我对矩阵的整个值进行排序而不是选择那些 k 值。我想假设 k 对于大型矩阵 m 有什么有效的方法,还有什么方法可以帮助我在想要获得前 k 列名称的情况下重复

例如:使用矩阵 mm,我需要识别具有最小值的前 2 列。在这里,对于以下情况,我期待第 1 列和第 2 列

mm = matrix(c(6,6,7,8,7,9,8,8,9), 3)
 print(mm)
     [,1] [,2] [,3]
[1,]    6    8    8
[2,]    6    7    8
[3,]    7    9    9
idx <- which(matrix(mm %in% head(sort(mm), 2), nr = nrow(mm)), arr.ind = TRUE)
print(idx)
      row col
[1,]   1   1
[2,]   2   1

但是,在这里我只得到一列,即; 1 ,在这种情况下,输出应该是两个具有最小值的不同列,即。 1和2

【问题讨论】:

  • 第一部分见this post。基本上,您使用sort.intpartial = TRUE 来加快排序速度。
  • 抱歉,我的意思是partial = 1:k
  • 感谢您的链接!它在某些方面很有用。
  • 对于新部分,如果您想知道哪两列包含最低值,可能类似于which( data.table::frank(matrixStats::colMins(mm), ties.method="dense") %in% 1:2 )

标签: r algorithm sorting matrix top-n


【解决方案1】:

以下是 OP 方法的比较,@Barker 建议替换 R 的部分排序功能和使用 quantile 的方法:

# example data
set.seed(1729)
n = 1e6
k = 50
m = matrix(runif(n), nr=10)

# illustration of the quantile way
which(m <= quantile(m, k/length(m)), arr.ind = TRUE)
# or...
library(data.table)
setDT(melt(m))[ value <= quantile(value, k/.N) ]
#    Var1  Var2        value
# 1:    8  4945 1.471722e-06
# 2:    1  7025 1.856475e-05
# 3:    9  7480 4.518987e-05
# 4:   10  8378 1.877453e-05
# 5:    2  9043 3.262958e-05
# 6:    7  9925 1.327880e-05
# 7:    5 13571 5.097035e-05
# ...

# benchmark
microbenchmark::microbenchmark(times = 30,
  idx  = idx <- which(matrix(m %in% head(sort(m), k), nr = nrow(m)), arr.ind = TRUE),
  dtq  = dtq <- setDT(melt(m))[ value <= quantile(value, k/.N) ],
  idxp = idxp <- which(matrix(m %in% head(sort(m, partial = 1:k), k), nr = nrow(m)), arr.ind = TRUE),
  idxq = idxq <- which(m <= quantile(m, k/length(m)), arr.ind = TRUE)
)

# verifying, requires data.table 1.9.7+
fsetequal(as.data.table(idx), dtq[, .(row = Var1, col = Var2)])
fsetequal(as.data.table(idxp), dtq[, .(row = Var1, col = Var2)])
fsetequal(as.data.table(idxq), dtq[, .(row = Var1, col = Var2)])

给了

Unit: milliseconds
 expr       min        lq      mean    median        uq       max neval  cld
  idx 145.01260 148.10571 155.27124 149.97761 152.45523 206.27179    30    d
  dtq  30.05910  33.11280  44.83088  35.02334  37.78721  90.92545    30  b  
 idxp 114.69501 118.23185 127.37992 119.50131 121.33241 175.41117    30   c 
 idxq  13.02406  14.47907  22.81266  16.41707  18.28308  68.53364    30 a   

我为这个例子去掉了 OP 的四舍五入。调整参数nk 可能会导致不同的方法排名。我的首选方式是setDT(melt(m))[order(value, partial = 1:k)],但它看起来在 R 中尚不可用。

【讨论】:

  • 感谢您对结果进行基准测试。我已经开始使用 idxq 方法。关于如何获得唯一的前 K 列,没有重复的任何想法/见解?
  • @rahul 我不确定你的意思。如果它有很大不同,您可能想将其作为一个新问题发布..?否则,也许你可以编辑这个问题来澄清,也许通过展示它对你的例子意味着什么。
  • 我已经编辑了这个问题来解释我所说的重复是什么意思。关系将是一个更好的术语。没有?
猜你喜欢
  • 2022-01-15
  • 2017-02-13
  • 2015-06-23
  • 1970-01-01
  • 2018-11-12
  • 2015-10-21
  • 2012-09-12
  • 1970-01-01
  • 2017-04-19
相关资源
最近更新 更多