Извлечение подматрицы из матрицы

#r #matrix #submatrix

Вопрос:

Я создаю матрицу в R размером 10×10 (10 строк и 10 столбцов): matriz <- matrix(1:100, nrow = 10, ncol = 10, byrow=T) я хочу извлечь квадратные подматрицы (3×3) из матрицы (матрицы) случайным образом и без перекрытия.

Я вижу пакет в R с именем «subset.matrix», но я не смог в случайной матрице.

Есть какие-нибудь предложения?

Комментарии:

1. Что вы имеете в виду случайно и без перекрытия? Сколько подматриц вы хотите «извлечь»? Если они не могут перекрываться, это не является полностью случайным?

2. Ой, извини! я имел в виду, что подматрицы могут быть взяты из любого места, если значения не совпадают

Ответ №1:

Вы можете определить следующую функцию f

 f <- function(mat, submat.size = 3) {
  ridx <- Filter(function(x) length(x) == submat.size, split(sample(seq(nrow(mat))), ceiling(seq(nrow(mat)) / submat.size)))
  cidx <- Filter(function(x) length(x) == submat.size, split(sample(seq(ncol(mat))), ceiling(seq(ncol(mat)) / submat.size)))
  replicate(2, mat[ridx[[sample(length(ridx), 1)]], cidx[[sample(length(cidx), 1)]]], simplify = FALSE)
}
 

и эта функция позволяет вам генерировать пару подматриц, которые являются случайными и не перекрывающимися.

Пример Результата

 > f(matriz)
[[1]]
     [,1] [,2] [,3]
[1,]   68   67   70
[2,]   38   37   40
[3,]   88   87   90

[[2]]
     [,1] [,2] [,3]
[1,]   63   62   69
[2,]   33   32   39
[3,]   83   82   89
 

Если вам нужны все возможные эксклюзивные случайные подматрицы каждый раз, вы можете попробовать

 f2 <- function(mat, submat.size = 3) {
  ridx <- Filter(function(x) length(x) == submat.size, split(sample(seq(nrow(mat))), ceiling(seq(nrow(mat)) / submat.size)))
  cidx <- Filter(function(x) length(x) == submat.size, split(sample(seq(ncol(mat))), ceiling(seq(ncol(mat)) / submat.size)))
  r <- list()
  for (i in seq_along(ridx)) {
    for (j in seq_along(cidx)) {
      r[[length(r)   1]] <- mat[ridx[[i]], cidx[[j]]]
    }
  }
  r
}
 

и вы получите

 > f2(matriz)
[[1]]
     [,1] [,2] [,3]
[1,]    3    6    5
[2,]   63   66   65
[3,]   83   86   85

[[2]]
     [,1] [,2] [,3]
[1,]    2    8    4
[2,]   62   68   64
[3,]   82   88   84

[[3]]
     [,1] [,2] [,3]
[1,]    1   10    7
[2,]   61   70   67
[3,]   81   90   87

[[4]]
     [,1] [,2] [,3]
[1,]   13   16   15
[2,]   33   36   35
[3,]   23   26   25

[[5]]
     [,1] [,2] [,3]
[1,]   12   18   14
[2,]   32   38   34
[3,]   22   28   24

[[6]]
     [,1] [,2] [,3]
[1,]   11   20   17
[2,]   31   40   37
[3,]   21   30   27

[[7]]
     [,1] [,2] [,3]
[1,]   43   46   45
[2,]   53   56   55
[3,]   73   76   75

[[8]]
     [,1] [,2] [,3]
[1,]   42   48   44
[2,]   52   58   54
[3,]   72   78   74

[[9]]
     [,1] [,2] [,3]
[1,]   41   50   47
[2,]   51   60   57
[3,]   71   80   77
 

Ответ №2:

Я согласен с комментарием пользователя 2974951 относительно случайности. Однако этот блок кода сделает то, о чем вы просили.

 matriz <- matrix(1:100, nrow = 10, ncol = 10, byrow=T)

attempts <- 50

# Initialize a list to hold the results
sub_mats <- vector(mode = "list", length = attempts)

# The top left corner of the matrix can't have an index > 8
rand_x <- sample(1:8, attempts, replace = T)
rand_y <- sample(1:8, attempts, replace = T)

for (i in 1:attempts) {
  # Get the three-length vectors
  x_range <- rand_x[i] : (rand_x[i]   2)
  y_range <- rand_y[i] : (rand_y[i]   2)
  # Subset the matrix
  sub_mat <- matriz[x_range, y_range]
  # We'll use NAs to mark submatrices from previous loops
  if (any(is.na(sub_mat))) next
  # If there's no overlap, add it to the list
  sub_mats[[i]] <- sub_mat
  # Set this submatrix as NAs
  matriz[x_range, y_range] <- rep(NA, 9)
}

# Remove failed attempts
sub_mats <- sub_mats[!sapply(sub_mats, is.null)]
 

Вместо установленного количества попыток для цикла вы можете использовать счетчик. С 50 попытками я получаю 4-6 подматриц. 1000 дает 6-8.