R: возвращает большую последовательную пару чисел в матрице

Я пытаюсь написать R-код, чтобы возвращать наибольшую последовательную пару чисел в матрице. Последовательные пары могут быть горизонтальными, вертикальными и обе диагоналями.

например если у меня есть матрица:

ma = array(c(8,4,3,1,7,5,9,15,6,10,16,11,2,14,12,13), dim = c(4,4))

самые высокие последовательные пары для (1) горизонтали: 16 и 12; (2) Вертикальный: 16 и 11 (3) диагональный(): 16 и 13; и (4) диагональ (/): 16 и 15.

Как я могу сделать это в R?

Ответ 1

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

directionalSums <- function(x){
  stopifnot(is.matrix(x))

  # padding functions to allow matrix addition
  padL  <- function(x) cbind(-Inf,x)
  padR  <- function(x) cbind(x,-Inf)
  padU  <- function(x) rbind(-Inf,x)
  padD  <- function(x) rbind(x,-Inf)

  # these padding functions are just for readability
  padLU <- function(x) padL(padU(x))
  padLD <- function(x) padL(padD(x))
  padRU <- function(x) padR(padU(x))
  padRD <- function(x) padR(padD(x))

  m <- nrow(x)
  n <- ncol(x)

  sumR <- padR( (padL(x) + padR(x))[1:m,2:n] )
  sumD  <- padD( (padU(x) + padD(x))[2:m,1:n])
  sumRD <- padRD( (padLU(x) + padRD(x))[2:m,2:n] )
  sumRU <- padRU( (padRU(x) + padLD(x))[2:m,2:n] )

  list(`right`=sumR, 
       `down`=sumD,
       `right and down`=sumRD,
       `right and up`=sumRU)

}

Попробуй.

(sumList <- directionalSums(ma))

maxLocList <- lapply(sumList, function(x) which(x==max(x), arr.ind=TRUE))

for (i in 1:length(maxLocList) ){
  nameD <- names(maxLocList)[i]
  startCell <- maxLocList[[i]]
  maxSum <- sumList[[i]][startCell]
  x1 <- ma[startCell]
  x2 <- maxSum - x1
  writeLines(paste0('The max-sum consec. pair going ',
                    nameD, ' starts at [',
                    paste(startCell, collapse=', '),
                    '], with sum ', maxSum,
                    ' and components ', x1, ' and ',x2)
             )
}

Возврат:

$right
     [,1] [,2] [,3] [,4]
[1,]   15   13    8 -Inf
[2,]    9   15   24 -Inf
[3,]   12   25   28 -Inf
[4,]   16   26   24 -Inf

$down
     [,1] [,2] [,3] [,4]
[1,]   12   12   16   16
[2,]    7   14   26   26
[3,]    4   24   27   25
[4,] -Inf -Inf -Inf -Inf

$`right and down`
     [,1] [,2] [,3] [,4]
[1,]   13   17   20 -Inf
[2,]   13   21   22 -Inf
[3,]   18   20   29 -Inf
[4,] -Inf -Inf -Inf -Inf

$`right and up`
     [,1] [,2] [,3] [,4]
[1,] -Inf -Inf -Inf -Inf
[2,]   11   11   12 -Inf
[3,]    8   19   30 -Inf
[4,]   10   31   23 -Inf

The max-sum consec. pair going right starts at [3, 3], with sum 28 and components 16 and 12
The max-sum consec. pair going down starts at [3, 3], with sum 27 and components 16 and 11
The max-sum consec. pair going right and down starts at [3, 3], with sum 29 and components 16 and 13
The max-sum consec. pair going right and up starts at [4, 2], with sum 31 and components 15 and 16

Ответ 2

Вот как это сделать, используя простой (но длинный) код.

Поскольку вы ищете пару с наибольшим последовательным, вы должны сначала создать функцию, которая берет ячейку и находит все ее последовательные суммы.

consec <- function(ma,y,x){
  return(
    c(if(x<ncol(ma))              ma[y,x] + ma[y,x+1],
      if(x>1)                     ma[y,x] + ma[y,x-1],
      if(y<nrow(ma))              ma[y,x] + ma[y+1,x],
      if(y>1)                     ma[y,x] + ma[y-1,x],
      if(x<ncol(ma) & y<nrow(ma)) ma[y,x] + ma[y+1,x+1],
      if(x>1 & y<nrow(ma))        ma[y,x] + ma[y+1,x-1],
      if(x<ncol(ma) & y>1)        ma[y,x] + ma[y-1,x+1],
      if(x>1 & y>1)               ma[y,x] + ma[y-1,x-1])
  )
}

В левой половине этой функции (операторы if) убедитесь, что мы не выходим за пределы, так как ячейка на границе будет иметь менее 8 соседей для формирования последовательной пары с. Правая половина затем получает сумму последовательной пары и добавляет ее в список.

Теперь, если вы используете consec(ma, 3, 2), он предоставит вам вектор сумм из последовательностей для ma[3,2].

Затем мы хотим заполнить вторую матрицу с наивысшей последовательной суммой для каждой ячейки. Вы можете использовать следующий код для создания пустой матрицы с правильными размерами.

ma2 <- matrix(0, nrow = nrow(ma), ncol = ncol(ma))

Теперь заполните его с помощью цикла и созданной ранее функции consec.

for(i in 1:nrow(ma)){
  for(j in 1:ncol(ma)){
    ma2[i,j] <- max(consec(ma,i,j)) 
  }
}

Теперь, когда у нас есть наша матрица последовательных сумм, мы можем найти в ней наибольшие суммы, а координаты ее будут соответствовать тому, где мы хотим посмотреть в исходной матрице.

ma.max <- which(ma2 == max(ma2), arr.ind = TRUE)

Теперь, если есть только одна пара чисел, которая является максимальной, то ma.max будет иметь две строки (две перестановки одной пары). Вы можете использовать:

ma[ma.max[1,1], ma.max[1,2]]; ma[ma.max[2,1], ma.max[2,2]]

Чтобы отобразить их. В этом случае мы получаем 15 и 16, чтобы он работал.

Если у вас больше максимальных значений, увеличьте числа в приведенном выше коде, чтобы получить следующую пару (3 и 4) и так далее. Вы можете даже настроить функцию consec, например, если вы не хотите, чтобы диагональные консигнанты удаляли последние четыре строки списка.