【问题标题】:How to store multidimensional subscript as variable in R如何将多维下标存储为R中的变量
【发布时间】:2018-03-05 04:57:48
【问题描述】:

假设我有一个矩阵,

mat <- matrix((1:9)^2, 3, 3)

我可以像这样对矩阵进行切片

> mat[2:3, 2]
[1] 25 36

如何将下标存储为变量?my_sub应该是什么,这样

> mat[my_sub]
[1] 25 36

list 出现“无效的下标类型”错误。向量将失去多维性。似乎这样一个基本操作没有适合这种用法的原始类型。

我知道我可以通过向量寻址访问矩阵,这意味着从[2:3, 2] 转换为c(5, 6),但该映射假定了解矩阵形状。如果我只是想要任何矩阵形状的[2:3, 2](假设它至少是那些尺寸)怎么办?

【问题讨论】:

    标签: r matrix multidimensional-array slice


    【解决方案1】:

    这里有一些替代方案。它们都可以推广到更高维的数组。

    1) 矩阵下标 如果索引都是标量,除了可能是一个,如问题中所示,那么:

    mi <- cbind(2:3, 2)
    mat[mi]
    
    # test
    identical(mat[mi],   mat[2:3, 2])
    ## [1] TRUE
    

    在更高维度:

    a <- array(1:24, 2:4)
    mi <- cbind(2, 2:3, 3)
    a[mi]
    
    # test
    identical(a[mi],   a[2, 2:3, 3])
    ## [1] TRUE
    

    可以使用以下方法扩展它以消除标量限制:

    L <- list(2:3, 2:3)
    array(mat[as.matrix(do.call(expand.grid, L))], lengths(L))
    

    然而,鉴于 (2) 也使用 do.call 但避免了对 expand.grid 的需要,它似乎不必要地复杂。

    2) do.call 这种方法没有标量限制。 mata 来自上方:

    L2 <- list(2:3, 1:2)
    do.call("[", c(list(mat), L2))
    
    # test
    identical(do.call("[", c(list(mat), L2)),   mat[2:3, 1:2])
    ## [1] TRUE
    
    
    L3 <- list(2, 2:3, 3:4)
    do.call("[", c(list(a), L3))
    
    # test
    identical(do.call("[", c(list(a), L3)),   a[2, 2:3, 3:4])
    ## [1] TRUE
    

    这可以通过定义变得更漂亮:

    `%[%` <- function(x, indexList) do.call("[", c(list(x), indexList))
    mat %[% list(2:3, 1:2)
    a %[% list(2, 2:3, 3:4)
    

    【讨论】:

    • 很好,但c(list(mat), list(2:3, 1:2)) 不只是list(mat, 2:3, 1:2)
    • 是的,但假设第二个列表是输入,所以它们必须放在一起。
    • 太棒了!您已经回答了我的核心问题,即my_sub 可以是一个矩阵。您可以使用以下方法进一步概括方法 (1) 来处理您在 (2) 中给出的案例:data.matrix(expand.grid(2, 2:3, 3:4))。唯一的缺点是它失去了结构。可能值得添加到答案中。
    【解决方案2】:

    使用which 参数arr.ind = TRUE

    x <- c(25, 36)
    inx <- which(mat == x, arr.ind = TRUE)
    Warning message:
    In mat == x :
      longer object length is not a multiple of shorter object length
    
    mat[inx]
    #[1] 25 36
    

    【讨论】:

    • 寻找与矩阵无关的东西,即没有关于值或形状的先验知识。
    【解决方案3】:

    这是一个有趣的问题。 subset 函数实际上可以提供帮助。您不能使用向量或列表直接对矩阵进行子集化,但您可以将索引存储在列表中并使用subset 来解决问题。

    mat <- matrix(1:12, nrow=4)
    mat[2:3, 1:2]
    # example using subset
    subset(mat, subset = 1:nrow(mat) %in% 2:3, select = 1:2)
    
    # double check
    identical(mat[2:3, 1:2], 
              subset(mat, subset = 1:nrow(mat) %in% 2:3, select = 1:2))
    
    # TRUE
    

    实际上,如果我们想将行索引和列索引存储在同一个列表中,我们可以编写一个自定义函数。

    cust.subset <- function(mat, dim.list){
      subset(mat, subset = 1:nrow(mat) %in% dim.list[[1]], select = dim.list[[2]])
    }
    
    # initialize a list that includes your sub-setting indexes
    sbdim <- list(2:3, 1:2)
    sbdim
    # [[1]]
    # [1] 2 3
    
    # [[2]]
    # [1] 1 2
    
    # subset using your custom f(x) and your list
    cust.subset(mat, sbdim)
    #      [,1] [,2]
    # [1,]    2    6
    # [2,]    3    7
    

    【讨论】:

    • 正在寻找我可以将my_sub 设置为等于的东西,而不是自定义访问器函数。但知道仍然有用。
    猜你喜欢
    • 2014-08-10
    • 2015-12-08
    • 1970-01-01
    • 1970-01-01
    • 2021-03-27
    • 1970-01-01
    • 2015-12-17
    • 2021-12-26
    • 1970-01-01
    相关资源
    最近更新 更多