根据向量元素及其位置提取矩阵值,并返回一个向量。

4
我有如下矩陣prob.matx:

prob.matx <- structure(c(0.182, 0.212, 0.364, 0.242, 0.242, 0.152, 0.394, 
                         0.212, 0.364, 0.091, 0.273, 0.273, 0.333, 0.242, 0.364, 0.061, 
                         0.273, 0.333, 0.212, 0.182, 0.303, 0.333, 0.182, 0.182), 
                       dim = c(4L, 6L), 
                       dimnames = list(c("A", "C", "G", "T"), 
                                       c("V1", "V2", "V3", "V4", "V5", "V6")))

看起来像这样:

     V1    V2    V3    V4    V5    V6
A 0.182 0.242 0.364 0.333 0.273 0.303
C 0.212 0.152 0.091 0.242 0.333 0.333
G 0.364 0.394 0.273 0.364 0.212 0.182
T 0.242 0.212 0.273 0.061 0.182 0.182

还有一个向量DNA

DNA <- c("A", "C", "C", "C", "C", "A")

我想根据 DNA 向量中的元素和位置提取矩阵值,并返回一个向量。也就是说:

c(prob.matx[DNA[1], 1], prob.matx[DNA[2], 2], prob.matx[DNA[3], 3], 
  prob.matx[DNA[4], 4], prob.matx[DNA[5], 5], prob.matx[DNA[6], 6])

[1] 0.182 0.152 0.091 0.242 0.333 0.303

这似乎很简单,但我很难找到一个一步函数来完成这个任务,不使用apply或for loop。

3个回答

4
我们可以对prob.matx进行索引,并提取diag值。
diag(prob.matx[DNA, ])

[1] 0.182 0.152 0.091 0.242 0.333 0.303

1
我删除了我的答案,它和你的一样,没有必要使用seq_along。 - zx8754
1
很好的答案,简明扼要!+1!唯一的缺点是对于长的 DNA 向量来说可能会占用过多内存。 - ThomasIsCoding

4
如果数组有维度名称,您可以使用一个每个维度的一列的字符矩阵进行索引。
prob.matx[cbind(DNA, colnames(prob.matx))]

# [1] 0.182 0.152 0.091 0.242 0.333 0.303

基准测试

prob.matx <- matrix(rnorm(26*100), 26, 100, dimnames = list(LETTERS, paste0('V', 1:100)))
DNA <- sample(LETTERS, 100, replace = TRUE)

bench::mark(
  "Darren" = prob.matx[cbind(DNA, colnames(prob.matx))],
  "benson23/zx8754" = diag(prob.matx[DNA, ])
)

# A tibble: 2 × 9
  expression           min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time
  <bch:expr>      <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm>
1 Darren             8.9µs    9.7µs    78756.    9.48KB     7.88  9999     1      127ms
2 benson23/zx8754   24.8µs   49.9µs    18694.   87.14KB    31.4   7737    13      414ms

1
好的回答,+1!使用prob.matx[cbind(match(DNA, row.names(prob.matx)), 1:ncol(prob.matx))]可以进一步改善,因为仅通过名称索引是不够的。你可以尝试更大的数据。 - ThomasIsCoding

3

我认为@Darren的答案在效率方面已经足够好了(除非你对速度有极高的要求)。我们实际上可以根据@Darren的解决方案进行一些不同的改进来提高速度。


让我们放眼更远,努力尝试

prob.matx <- matrix(rnorm(26 * 1000), 26, 10000, dimnames = list(LETTERS, paste0("V", 1:10000)))
DNA <- sample(LETTERS, 100000, replace = TRUE)

bench::mark(
  "Darren" = prob.matx[cbind(DNA, colnames(prob.matx))],
  "TIC" = prob.matx[cbind(match(DNA, row.names(prob.matx)), 1:ncol(prob.matx))]
)

然后我们会看到

# A tibble: 2 × 13
  expression      min  median itr/s…¹ mem_a…² gc/se…³ n_itr  n_gc total…⁴ result
  <bch:expr> <bch:tm> <bch:t>   <dbl> <bch:b>   <dbl> <int> <dbl> <bch:t> <list>
1 Darren       4.14ms  4.57ms    207.  6.69MB    19.3    86     8   415ms <dbl>
2 TIC           1.5ms     2ms    502.  3.09MB    18.9   213     8   424ms <dbl>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接