【问题标题】:R: return largest consecutive pair of numbers in a matrixR:返回矩阵中最大的连续数字对
【发布时间】:2017-01-18 22:31:50
【问题描述】:

我正在尝试编写一个 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 中做到这一点?

【问题讨论】:

  • s <- ma[1:3,] + ma[2:4,]; which(s == max(s), arr.ind = TRUE) for 获取行对中第一个的索引;它的对将在它的正下方。对于列,您只需翻转逗号即可。对角线会做更多的工作。
  • 对角线应该只是s <- ma[1:3,1:3] + ma[2:4,2:4]; which(s == max(s), arr.ind = TRUE) 否?
  • 您在寻找总和最大的连续对吗?否则,你如何比较对?

标签: r matrix


【解决方案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]]
    

    显示它们。在这种情况下,我们得到了1516,所以它起作用了。

    如果您有更多的最大值,则增加上述代码中的数字以获得下一对(3 和 4),依此类推。您甚至可以调整 consec 函数,例如,如果您不希望对角线连续,则删除列表的最后四行。

    【讨论】:

      猜你喜欢
      • 2014-02-27
      • 1970-01-01
      • 1970-01-01
      • 2014-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-18
      • 1970-01-01
      相关资源
      最近更新 更多