使用行号矩阵从矩阵中提取数值矩阵

编程语言 2026-07-10

我想要 高效地 从一个矩阵(vals)中提取值,使用一个单列号(val_col),以及一个行号矩阵(val_rows)。具体来说,我还希望我的 结果val_rows 对应的矩阵形式。

# Matrix of values.
n_cols <- 3
n_rows <- 5
n_vals <- n_cols * n_rows

vals <- outer(
  seq_len(n_rows), seq_len(n_cols),
  paste, sep = "x"
)

vals
#>      [,1]  [,2]  [,3] 
#> [1,] "1x1" "1x2" "1x3"
#> [2,] "2x1" "2x2" "2x3"
#> [3,] "3x1" "3x2" "3x3"
#> [4,] "4x1" "4x2" "4x3"
#> [5,] "5x1" "5x2" "5x3"


# Column number.
val_col <- 2


# Matrix of row numbers.
n_rows_out <- 4
n_vals_out <- n_cols * n_rows_out

set.seed(111)
val_rows <- sample.int(n_rows, size = n_vals_out, replace = TRUE) |>
  matrix(ncol = n_cols, byrow = TRUE)

val_rows
#>      [,1] [,2] [,3]
#> [1,]    3    4    3
#> [2,]    1    3    5
#> [3,]    3    4    2
#> [4,]    1    5    5

现在我 想要 的结果是一个这样的矩阵:

result <- structure(
  c("3x2", "1x2", "3x2", "1x2", "4x2", "3x2", "4x2", "5x2", "3x2", "5x2", "2x2", "5x2"),
  dim = 4:3
)

result
#>      [,1]  [,2]  [,3] 
#> [1,] "3x2" "4x2" "3x2"
#> [2,] "1x2" "3x2" "5x2"
#> [3,] "3x2" "4x2" "2x2"
#> [4,] "1x2" "5x2" "5x2"

但当我仅用 [ 进行提取时,我的结果被“展平”为一个向量。

result <- vals[val_rows, val_col]

result
#>  [1] "3x2" "1x2" "3x2" "1x2" "4x2" "3x2" "4x2" "5x2" "3x2" "5x2" "2x2" "5x2"

即使我指定 drop = FALSE,矩阵也并不像 val_rows 那样有结构。

result <- vals[val_rows, val_col, drop = FALSE]

result
#>       [,1] 
#>  [1,] "3x2"
#>  [2,] "1x2"
#>  [3,] "3x2"
#>  [4,] "1x2"
#>  [5,] "4x2"
#>  [6,] "3x2"
#>  [7,] "4x2"
#>  [8,] "5x2"
#>  [9,] "3x2"
#> [10,] "5x2"
#> [11,] "2x2"
#> [12,] "5x2"

看来我可以在一行内简单地修改 dim()

result <- vals[val_rows, val_col] |>
  `dim<-`(c(n_rows_out, n_cols))

result
#>      [,1]  [,2]  [,3] 
#> [1,] "3x2" "4x2" "3x2"
#> [2,] "1x2" "3x2" "5x2"
#> [3,] "3x2" "4x2" "2x2"
#> [4,] "1x2" "5x2" "5x2"


result <- vals[val_rows, val_col, drop = TRUE] |>
  `dim<-`(c(n_rows_out, n_cols))

result
#>      [,1]  [,2]  [,3] 
#> [1,] "3x2" "4x2" "3x2"
#> [2,] "1x2" "3x2" "5x2"
#> [3,] "3x2" "4x2" "2x2"
#> [4,] "1x2" "5x2" "5x2"

显然,我可以把向量输入到 matrix() 中,使其重组成与 val_rows 相同的结构。

result <- vals[val_rows, val_col] |>
  matrix(ncol = n_cols, byrow = FALSE)

result
#>      [,1]  [,2]  [,3] 
#> [1,] "3x2" "4x2" "3x2"
#> [2,] "1x2" "3x2" "5x2"
#> [3,] "3x2" "4x2" "2x2"
#> [4,] "1x2" "5x2" "5x2"

但如果我记错了,通过 matrix() 填充值在大规模重复时效率并不高。我们难道不应该把整个结果按值传递给 dim() 以便就地修改其 dim 属性吗?

无论如何,这些做法冗余地“修复”本不应该发生的“损坏”。 那么,在保持 val_rows 结构的前提下,提取值的最有效方法是什么?

解决方案

是的,高效的解决方案就是在提取后重新恢复维度。

[ 在这里返回一个向量,因为矩阵索引在R 中遵循列主序。由于矩阵在R 中按列存储,vals[val_rows, val_col] 的结果已经按照与 val_rows 相同维度的矩阵的内部顺序排列。

所以你可以这样做:

result <- vals[val_rows, val_col]
dim(result) <- dim(val_rows)

result
#      [,1]  [,2]  [,3]
# [1,] "#8"  "#11" "#8"
# [2,] "#2"  "#8"  "#14"
# [3,] "#8"  "#11" "#5"
# [4,] "#2"  "#14" "#14"
# [5,] "#5"  "#11" "#5"

这会得到与 val_rows 相对应的逐元素正确结果。

如果你想要一行代码:

result <- structure(vals[val_rows, val_col], dim = dim(val_rows))

或者,更明确地说:

result <- structure(vals[cbind(c(val_rows), val_col)], dim = dim(val_rows))

一个重要点是:matrix(..., byrow = TRUE) 在这里并不合适——它按行重新排序提取的值,而索引结果是按列主序生成的。

在R 层面,没有能保留索引矩阵形状的特殊提取形式:[ 返回一个向量,所以恢复 dim 是标准解决办法。因为在R 中,矩阵/数组本质上只是带有 "dim" 属性的向量:

dim(result) <- dim(val_rows)

至于复制:R使用的是copy-on-modify语义,因此来自R 代码的真正就地变更并不一定会发生。设置 dim 当对象未被共享时可能成本较低,但实际是否会发生复制,是实现细节,你不能依赖。

在纯R 中,dim<- / structure(..., dim = ...) 是惯用且高效的答案。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章