Высокомерный массив - PullRequest
       7

Высокомерный массив

0 голосов
/ 28 января 2020

У меня есть 13-мерный массив: MatrixQ <-array (0, dim = c (2,2,2,2,2,2,2,2,2,2,2,2,3)) </p>

Как я могу сослаться на его i-е измерение в al oop?

for (i в 1:13) {Я хочу присвоить число i i-му измерению массива } Какую команду я должен использовать? Спасибо,

Ответы [ 3 ]

0 голосов
/ 29 января 2020
at <- function(array = a, d = 1, slice = 1)
{
  consec <- cumprod(c(1, dim(a)))[-(length(dim(a)) + 1)]
  skip_n <- consec * (dim(a) - 1)
  basic_pattern <- rep_len(c(rep(TRUE, consec[d]), rep(FALSE, skip_n[d])), length(a))
  which(c(rep(FALSE, consec[d] * (slice - 1)), basic_pattern)[seq_along(a)])
}



StartPoint1QQQ <- array(c(1,1,0,0))
StartPoint2QQQ <- array(c(1,1,0,0))+1
MatrixQQQ<-array(0,dim=c(2,2,2,2))
MatrixQQQ[2,2,1,1] <- 0.1
MatrixQQQ[2,2,2,1] <- 0.2
MatrixQQQ[2,2,1,2] <- 5
for(j in 2:4)
{

  if(StartPoint2QQQ[j] == 1)
 {

    Indexlist2 <- which( MatrixQQQ[at(MatrixQQQ, j, 1)] == max( MatrixQQQ[at(MatrixQQQ, j, 1)]), arr.ind = TRUE)
  }
}
#I simplified my higher dimension problem. MatrixQQQ is my 4 dimensional matrix that stores 
#scores for each state (there are 4 states). Here the first state is time, and 2nd-4th states are cost.
#I care for cost only for now, so states 2:4 are of interest. I want to get a list of indices 
# in which the slice is 1 and among them find the ones with maximum MatrixQQQ value

#The expected value here is 2,2,1,2 because its MatrixQQQ value is the highest, 5.
0 голосов
/ 30 января 2020
at <- function(Array, Dimension, Slice, index = FALSE)
{
  if(!is.array(Array)) 
    stop("'at()' can only be called on arrays")

  if(!(is.numeric(Dimension) && Dimension > 0))
    stop("Invalid value of Dimension supplied to 'at()'")

  # Get the numbers of dimensions and elements in our Array
  n       <- length(Array)
  dims    <- dim(Array)
  n_dims  <- length(dims)

  if(Dimension > n_dims | Dimension < 1) 
    stop("Invalid dimension chosen in 'at()'")

  if(max(Slice) > dims[Dimension]) 
    stop("Invalid slice chosen for given dimension")

  final_result <- numeric()

  for(i in seq_along(Slice))
  {
    run_length  <- cumprod(c(1, dims)[-(n_dims + 1)])[Dimension]
    skip_length <- run_length * (dims[Dimension] - 1)

    # Now we simply make a repeating pattern of membership / non-membership
    pattern         <- rep_len(c(rep(T, run_length), rep(F, skip_length)), n)
    shifted_pattern <- c(rep(FALSE, run_length * (Slice[i] - 1)), pattern)
    loop_result     <- which(shifted_pattern[seq(n)])
    final_result    <- c(final_result, loop_result)
  }
   if(index == FALSE)
  {
    dims[Dimension] <- length(Slice)
    return(array(Array[final_result], dim = dims))
  }
  return(sort(final_result))
}


IMAX <- 2

MatrixQ<-array(0,dim=c(2,2,2,2,2,2,2,2,2,2,2,2,3))
MatrixQ[2,2,1,1,1,1,1,1,1,2,1,2,IMAX] <- 5000

j <- 10


which(MatrixQ == max(MatrixQ), arr.ind = T)

which(at(MatrixQ, j, 2) == max(at(MatrixQ, j, 2)), arr.ind = T)



######ANSWER I GET:###########################
####which(MatrixQ == max(MatrixQ), arr.ind = T)
####      dim1 dim2 dim3 dim4 dim5 dim6 dim7 dim8 dim9 dim10 dim11 dim12 dim13
####[1,]    2    2    1    1    1    1    1    1    1     2     1     2     2

####> which(at(MatrixQ, j, 2) == max(at(MatrixQ, j, 2)), arr.ind = T)
####       dim1 dim2 dim3 dim4 dim5 dim6 dim7 dim8 dim9 dim10 dim11 dim12 dim13
####[1,]    2    2    1    1    1    1    1    1    1     1     1     2     2
0 голосов
/ 29 января 2020

Насколько мне известно, не существует простого способа сделать это встроенным в R. Однако вы можете воспользоваться тем фактом, что массив на самом деле хранится как вектор с атрибутом измерения (dim). Таким образом, вы можете получить доступ к элементам напрямую, без использования нескольких запятых. Сложность состоит в том, чтобы определить, какие индексы базового вектора представляют нужный фрагмент массива. Это просто требует немного математики.

Я думаю, вы ищете что-то вроде этого:

at <- function(Array, Dimension, Slice, index = FALSE)
{
  if(!is.array(Array)) 
    stop("'at()' can only be called on arrays")

  if(!(is.numeric(Dimension) && Dimension > 0))
    stop("Invalid value of Dimension supplied to 'at()'")

  # Get the numbers of dimensions and elements in our Array
  n       <- length(Array)
  dims    <- dim(Array)
  n_dims  <- length(dims)

  if(Dimension > n_dims | Dimension < 1) 
    stop("Invalid dimension chosen in 'at()'")

  if(max(Slice) > dims[Dimension]) 
    stop("Invalid slice chosen for given dimension")

  final_result <- numeric()

  for(i in seq_along(Slice))
  {
    run_length  <- cumprod(c(1, dims)[-(n_dims + 1)])[Dimension]
    skip_length <- run_length * (dims[Dimension] - 1)

    # Now we simply make a repeating pattern of membership / non-membership
    pattern         <- rep_len(c(rep(T, run_length), rep(F, skip_length)), n)
    shifted_pattern <- c(rep(FALSE, run_length * (Slice[i] - 1)), pattern)
    loop_result     <- which(shifted_pattern[seq(n)])
    final_result    <- c(final_result, loop_result)
  }
  if(index == FALSE)
  {
    dims[Dimension] <- length(Slice)
    return(array(Array[final_result], dim = dims))
  }
  return(sort(final_result))
}

Вот как вы можете использовать это. Начнем с массива (давайте всего 3 измерения)

my_array <- array(0, dim = c(2, 3, 4))
my_array
#> , , 1
#> 
#>      [,1] [,2] [,3]
#> [1,]    0    0    0
#> [2,]    0    0    0
#> 
#> , , 2
#> 
#>      [,1] [,2] [,3]
#> [1,]    0    0    0
#> [2,]    0    0    0
#> 
#> , , 3
#> 
#>      [,1] [,2] [,3]
#> [1,]    0    0    0
#> [2,]    0    0    0
#> 
#> , , 4
#> 
#>      [,1] [,2] [,3]
#> [1,]    0    0    0
#> [2,]    0    0    0

Теперь я могу получить индексы базового массива, которые представляют 2-ю матрицу третьего измерения (то есть my_array[, , 2]), например:

at(my_array, 3, 2, index = T)
# [1]  7  8  9 10 11 12

Это означает, что если я напишу что-нибудь в my_array[c(7, 8, 9, 10, 11, 12)], это изменит элементы в соответствующем срезе матрицы:

my_array[at(my_array, 3, 2, index = T)] <- 69
my_array
#> , , 1
#> 
#>      [,1] [,2] [,3]
#> [1,]    0    0    0
#> [2,]    0    0    0
#> 
#> , , 2
#> 
#>      [,1] [,2] [,3]
#> [1,]   69   69   69
#> [2,]   69   69   69
#> 
#> , , 3
#> 
#>      [,1] [,2] [,3]
#> [1,]    0    0    0
#> [2,]    0    0    0
#> 
#> , , 4
#> 
#>      [,1] [,2] [,3]
#> [1,]    0    0    0
#> [2,]    0    0    0

И, конечно, это означает, что мы можем сделать все oop где мы можем выбрать размеры. Здесь мы сначала сбросим my_array в нули, а затем поместим номер измерения в каждый элемент в первом срезе в этом измерении. Обратите внимание, что некоторые ячейки перезаписываются в процессе, если они принадлежат первому срезу нескольких измерений.

# Reset my_array first
my_array[] <- 0

for(i in 1:3)
{
  my_array[at(my_array, i, 1, index = T)] <- i;
}
my_array
#> , , 1
#> 
#>      [,1] [,2] [,3]
#> [1,]    3    3    3
#> [2,]    3    3    3
#> 
#> , , 2
#> 
#>      [,1] [,2] [,3]
#> [1,]    2    1    1
#> [2,]    2    0    0
#> 
#> , , 3
#> 
#>      [,1] [,2] [,3]
#> [1,]    2    1    1
#> [2,]    2    0    0
#> 
#> , , 4
#> 
#>      [,1] [,2] [,3]
#> [1,]    2    1    1
#> [2,]    2    0    0

Хотя пример для трехмерного массива, это должно работать для любого числа измерений.

Причина index = T заключается в том, что, опуская это, мы можем напрямую получить нужный фрагмент без использования индексации:

at(my_array, 3, 1:2)
#> , , 1
#> 
#>      [,1] [,2] [,3]
#> [1,]    3    3    3
#> [2,]    3    3    3
#> 
#> , , 2
#> 
#>      [,1] [,2] [,3]
#> [1,]    2    1    1
#> [2,]    2    0    0

Например, в ответе ОП вы можете использовать это сделать следующим образом:

Indexlist2 <- numeric()

for(j in 2:4)
{
 if(StartPoint2QQQ[j] == 1)
 {
    j_matches <- which(at(MatrixQQQ, j, 1) == max(at(MatrixQQQ, j, 1)), arr.ind = T)
    Indexlist2 <- rbind(Indexlist2, j_matches)
  }
}

Теперь у нас есть

Indexlist2
#>      dim1 dim2 dim3 dim4
#> [1,]    2    2    1    2
#> [2,]    2    2    2    1

MatrixQQQ[Indexlist2]
#> [1] 5.0 0.2
...