构建具有指定数量单元格的square-ish矩阵

Tho*_*mas 4 r matrix sequence

我想编写一个函数来转换整数,n(指定矩阵中的单元格数)为包含序列的square-ish矩阵1:n.目标是使矩阵尽可能"正方形".

这涉及以下几点:

  1. 如何最大化"方形" - 性?我正在考虑等于矩阵尺寸差异的惩罚penalty <- abs(dim(mat)[1]-dim(mat)[2]),例如,penalty==0当矩阵是正方形时,否则是正的.理想情况下,这将例如n==12导致偏好3x4而不是2x6矩阵.但我不确定最好的方法.

  2. 帐户的奇数值n.奇数值n不一定会产生明显的矩阵选择(除非它们有一个整数平方根,比如n==9.我想简单地加1 n,然后处理为偶数并允许一个空白单元,但我'我不确定这是否是最好的方法.我想可能通过添加多于1来获得更方形的矩阵(通过1中的定义)n.

  3. 允许该函数权衡平方(如#1中所述)和空白单元格的数量(如#2中所述),因此该函数应具有某种参数来解决这种权衡问题.例如,对于n==11,3x4矩阵是相当正方形但不像4x4那样正方形,但4x4将具有比3x4更多的空白单元.

  4. 该函数需要选择性地生成更宽或更高的矩阵,以便n==12生成3x4或4x3矩阵.但是使用t()生成的矩阵很容易处理.


这是一些预期的输出:

> makemat(2)
     [,1]
[1,]    1
[2,]    2

> makemat(3)
     [,1] [,2]
[1,]    1    3
[2,]    2    4

> makemat(9)
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9

> makemat(11)
     [,1] [,2] [,3] [,4]
[1,]    1    4    7    10
[2,]    2    5    8    11
[3,]    3    6    9    12
Run Code Online (Sandbox Code Playgroud)

这个问题基本上是一个非常糟糕的开端.

makemat <- function(n) {
    n <- abs(as.integer(n))
    d <- seq_len(n)
    out <- d[n %% d == 0]
    if(length(out)<2)
        stop('n has fewer than two factors')
    dim1a <- out[length(out)-1]
    m <- matrix(1:n, ncol=dim1a)
    m
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我实际上无法解释奇数值n(查看#2 中的输出makemat(7)makemat(11)描述,或强制执行#1中描述的"方形"规则,或权衡取舍他们之间如#3所述.

Rei*_*son 12

我认为您想要的逻辑已经在效用函数中n2mfrow(),顾名思义就是创建mfrow图形参数的输入并获取整数输入并返回行和列中的面板数量以将显示拆分为:

> n2mfrow(11)
[1] 4 3
Run Code Online (Sandbox Code Playgroud)

它有利于高布局而不是宽布局,但很容易通过rev()输出或t()由结果产生的矩阵来固定n2mfrow().

makemat <- function(n, wide = FALSE) {
  if(isTRUE(all.equal(n, 3))) {
    dims <- c(2,2)
  } else {
    dims <- n2mfrow(n)
  }
  if(wide)
    dims <- rev(dims)
  m <- matrix(seq_len(prod(dims)), nrow = dims[1], ncol = dims[2])
  m
}
Run Code Online (Sandbox Code Playgroud)

注意我必须特殊情况,n = 3因为我们滥用一个用于其他用途的函数,并且绘图上的3x1布局比具有空白空间的2x2更有意义.

在使用中我们有:

> makemat(2)
     [,1]
[1,]    1
[2,]    2
> makemat(3)
     [,1] [,2]
[1,]    1    3
[2,]    2    4
> makemat(9)
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9
> makemat(11)
     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6   10
[3,]    3    7   11
[4,]    4    8   12
> makemat(11, wide = TRUE)
     [,1] [,2] [,3] [,4]
[1,]    1    4    7   10
[2,]    2    5    8   11
[3,]    3    6    9   12
Run Code Online (Sandbox Code Playgroud)

编辑:

原有的功能填充seq_len(n)NA,但我意识到了OP想有从1到一个序列prod(nrows, ncols),这是上面的版本一样.下面垫一个NA.

makemat <- function(n, wide = FALSE) {
  if(isTRUE(all.equal(n, 3))) {
    dims <- c(2,2)
  } else {
    dims <- n2mfrow(n)
  }
  if(wide)
    dims <- rev(dims)
  s <- rep(NA, prod(dims))
  ind <- seq_len(n)
  s[ind] <- ind
  m <- matrix(s, nrow = dims[1], ncol = dims[2])
  m
}
Run Code Online (Sandbox Code Playgroud)


nog*_*pes 6

我认为这个函数隐含地满足了你的约束.参数范围为0到Inf.该函数总是返回一个边长的方形矩阵ceiling(sqrt(n)),或者一个(可能)矩形矩阵,其中有行floor(sqrt(n))和足够的列来"填充".该参数对两者之间的选择进行折衷:如果它小于1,则优选第二个更矩形的矩阵,如果大于1,则优选第一个,总是正方形的矩阵.A中param的1对它们的权重相等.

makemat<-function(n,param=1,wide=TRUE){
  if (n<1) stop('n must be positive')
  s<-sqrt(n)
  bottom<-n-(floor(s)^2)
  top<-(ceiling(s)^2)-n
  if((bottom*param)<top) {
      rows<-floor(s)
      cols<-rows + ceiling(bottom / rows) 
  } else {
    cols<-rows<-ceiling(s)
  }
  if(!wide) {
    hold<-rows
    rows<-cols
    cols<-hold
  }
  m<-seq.int(rows*cols)
  dim(m)<-c(rows,cols)
  m
}
Run Code Online (Sandbox Code Playgroud)

下面是一个参数设置为默认值的示例,同样平均距离:

lapply(c(2,3,9,11),makemat)

# [[1]]
#      [,1] [,2]
# [1,]    1    2
# 
# [[2]]
#      [,1] [,2]
# [1,]    1    3
# [2,]    2    4
# 
# [[3]]
#      [,1] [,2] [,3]
# [1,]    1    4    7
# [2,]    2    5    8
# [3,]    3    6    9
# 
# [[4]]
#      [,1] [,2] [,3] [,4]
# [1,]    1    4    7   10
# [2,]    2    5    8   11
# [3,]    3    6    9   12
Run Code Online (Sandbox Code Playgroud)

下面是使用带有11的param来获得4x4矩阵的示例.

makemat(11,3)
#      [,1] [,2] [,3] [,4]
# [1,]    1    5    9   13
# [2,]    2    6   10   14
# [3,]    3    7   11   15
# [4,]    4    8   12   16   
Run Code Online (Sandbox Code Playgroud)