首页 > 解决方案 > 是否有 R 函数可以从矩阵中获取所有可能的子矩阵?

问题描述

如果我有一个像下面这样的矩阵,我想根据第一列对其进行分组并创建子矩阵的所有组合,其中子矩阵的行数将等于创建的组数,如示例所示。在 R 中有没有有效的方法来做到这一点?我试图使用 tidyverse group_by(),但找不到正确的函数来获取子矩阵。

# Input Matrix
  [,1] [,2] [,3]
[1,] "a"  "1"  "6" 
[2,] "a"  "5"  "9" 
[3,] "c"  "7"  "4" 
[4,] "b"  "5"  "4" 
[5,] "a"  "6"  "4" 
[6,] "b"  "6"  "4" 
[7,] "b"  "4"  "3" 
[8,] "c"  "1"  "2" 
[9,] "d"  "9"  "9" 


# Want to create a Group Matrix
grp1
[1,] "a"  "1"  "6" 
[2,] "a"  "5"  "9" 
[5,] "a"  "6"  "4" 

grp2
[4,] "b"  "5"  "4" 
[6,] "b"  "6"  "4" 
[7,] "b"  "4"  "3" 

grp3
[3,] "c"  "7"  "4" 
[8,] "c"  "1"  "2" 

grp4
[9,] "d"  "9"  "9" 



# Then create - All Combination Submatrix
s1
[1,] "a"  "1"  "6" 
[4,] "b"  "5"  "4" 
[3,] "c"  "7"  "4" 
[9,] "d"  "9"  "9"
s2
[1,] "a"  "1"  "6" 
[6,] "b"  "6"  "4" 
[8,] "c"  "1"  "2" 
[9,] "d"  "9"  "9"
s3
[1,] "a"  "1"  "6" 
[7,] "b"  "4"  "3"
[3,] "c"  "7"  "4"
[9,] "d"  "9"  "9" 

and so on...

标签: rtidyr

解决方案


我们可以用 dplyr 和 purrr 来做到这一点。

首先,要按组获取单独的数据帧,我们可以使用 dplyr 的group_split

library(dplyr)
library(purrr)

g <- c("a", "a", "c", "b", "a", "b", "b", "c", "d")
m1 <- c(1, 5, 7, 5, 6, 6, 4, 1, 9)
m2 <- c(6, 9, 4, 4, 4, 4, 3, 2, 9)

df <- tibble(g = g, m1 = m1, m2 = m2)

df %>%
  group_split(g)
#> [[1]]
#> # A tibble: 3 x 3
#>   g        m1    m2
#>   <chr> <dbl> <dbl>
#> 1 a         1     6
#> 2 a         5     9
#> 3 a         6     4
#>
#> .......
#>
#> [[4]]
#> # A tibble: 1 x 3
#>   g        m1    m2
#>   <chr> <dbl> <dbl>
#> 1 d         9     9
#> 
#> attr(,"ptype")
#> # A tibble: 0 x 3
#> # … with 3 variables: g <chr>, m1 <dbl>, m2 <dbl>

要获取每个组的所有行组合,我们将遵循以下过程:

  1. 按我们想要的变量分组 ( group_by(g))
  2. 提取变量的每个值g出现的行号列表(使用 dplyr's group_rows)。列表的第一个元素将是一个列表,其中包含 g 等于“a”的行号,g 等于“b”的第二个元素,等等。
  3. 使用 purrr's 展开此列表中元素的所有组合cross。这为我们提供了一个列表,其中每个元素都包含所需子矩阵之一的行。
  4. 使用每组索引对矩阵进行子集,一次使用 purrr's map。根据需要,这为我们留下了所有可能的子矩阵的列表。
df %>% 
  group_by(g) %>%
  group_rows() %>%
  cross() %>%
  map(., ~df %>% slice(flatten_int(.x)))
#> [[1]]
#> # A tibble: 4 x 3
#>   g        m1    m2
#>   <chr> <dbl> <dbl>
#> 1 a         1     6
#> 2 b         5     4
#> 3 c         7     4
#> 4 d         9     9
#> 
#> [[2]]
#> # A tibble: 4 x 3
#>   g        m1    m2
#>   <chr> <dbl> <dbl>
#> 1 a         5     9
#> 2 b         5     4
#> 3 c         7     4
#> 4 d         9     9
#> 
#> [[3]]
#> # A tibble: 4 x 3
#>   g        m1    m2
#>   <chr> <dbl> <dbl>
#> 1 a         6     4
#> 2 b         5     4
#> 3 c         7     4
#> 4 d         9     9
#>
#> .......
#> 
#> [[18]]
#> # A tibble: 4 x 3
#>   g        m1    m2
#>   <chr> <dbl> <dbl>
#> 1 a         6     4
#> 2 b         4     3
#> 3 c         1     2
#> 4 d         9     9

请记住,尽管您将创建的子矩阵的数量随着每个组中的行数的乘积而增长g(组'a'中的行数乘以组'b'中的行数,乘以.. .)。

例如,如果您只有 16 个组,每个组有 10 行,cross将尝试创建一个长度为 10^16 的整数向量。这个长度大于 R 规定的 52 位最大值,更确切地说,远远大于你的机器在内存中可以容纳的长度——这样的向量需要大约 37 PB。


推荐阅读