我有一个16行12列的矩阵M,我想把它分成16个矩阵的数组,每个矩阵有4行3列。我可以通过以下方式手动完成:
M = matrix(sample(0:127,16*12,replace=TRUE), c(16,12))
ma1 = M[1:4,1:3]
ma2 = M[1:4,4:6]
ma3 = M[1:4,7:9]
ma4 = M[1:4,10:12]
ma5 = M[5:8,1:3]
ma6 = M[5:8,4:6]
.....
但是如何创建一个通用函数matsplitter(M,r,c),它将M分成矩阵数组,每个矩阵都有r行和c列?
感谢您的帮助。
答案 0 :(得分:17)
如果您有像这样的16x12阵列
mb <- structure(c("a1", "a2", "a3", "a4", "e1", "e2", "e3", "e4", "i1",
"i2", "i3", "i4", "m1", "m2", "m3", "m4", "a5", "a6", "a7", "a8",
"e5", "e6", "e7", "e8", "i5", "i6", "i7", "i8", "m5", "m6", "m7",
"m8", "a9", "a10", "a11", "a12", "e9", "e10", "e11", "e12", "i9",
"i10", "i11", "i12", "m9", "m10", "m11", "m12", "b1", "b2", "b3",
"b4", "f1", "f2", "f3", "f4", "j1", "j2", "j3", "j4", "n1", "n2",
"n3", "n4", "b5", "b6", "b7", "b8", "f5", "f6", "f7", "f8", "j5",
"j6", "j7", "j8", "n5", "n6", "n7", "n8", "b9", "b10", "b11",
"b12", "f9", "f10", "f11", "f12", "j9", "j10", "j11", "j12",
"n9", "n10", "n11", "n12", "c1", "c2", "c3", "c4", "g1", "g2",
"g3", "g4", "k1", "k2", "k3", "k4", "o1", "o2", "o3", "o4", "c5",
"c6", "c7", "c8", "g5", "g6", "g7", "g8", "k5", "k6", "k7", "k8",
"o5", "o6", "o7", "o8", "c9", "c10", "c11", "c12", "g9", "g10",
"g11", "g12", "k9", "k10", "k11", "k12", "o9", "o10", "o11",
"o12", "d1", "d2", "d3", "d4", "h1", "h2", "h3", "h4", "l1",
"l2", "l3", "l4", "p1", "p2", "p3", "p4", "d5", "d6", "d7", "d8",
"h5", "h6", "h7", "h8", "l5", "l6", "l7", "l8", "p5", "p6", "p7",
"p8", "d9", "d10", "d11", "d12", "h9", "h10", "h11", "h12", "l9",
"l10", "l11", "l12", "p9", "p10", "p11", "p12"), .Dim = c(16L,
12L))
您可以将matsplitter
定义为
matsplitter<-function(M, r, c) {
rg <- (row(M)-1)%/%r+1
cg <- (col(M)-1)%/%c+1
rci <- (rg-1)*max(cg) + cg
N <- prod(dim(M))/r/c
cv <- unlist(lapply(1:N, function(x) M[rci==x]))
dim(cv)<-c(r,c,N)
cv
}
然后
matsplitter(mb,4,3)
将返回(输出剪辑)
, , 1
[,1] [,2] [,3]
[1,] "a1" "a5" "a9"
[2,] "a2" "a6" "a10"
[3,] "a3" "a7" "a11"
[4,] "a4" "a8" "a12"
, , 2
[,1] [,2] [,3]
[1,] "b1" "b5" "b9"
[2,] "b2" "b6" "b10"
[3,] "b3" "b7" "b11"
[4,] "b4" "b8" "b12"
, , 3
[,1] [,2] [,3]
[1,] "c1" "c5" "c9"
[2,] "c2" "c6" "c10"
[3,] "c3" "c7" "c11"
[4,] "c4" "c8" "c12"
...
答案 1 :(得分:9)
这是一个使用Kronecker产品做同样事情的功能。为什么?因为我喜欢Kronecker的产品。这里的好处是,如果你的行和列值没有均匀地划分到输入矩阵中,那么这个函数将用NA填充右边和底边的较小矩阵,这样你仍然可以有一个数组输出。
mat_split <- function(M, r, c){
nr <- ceiling(nrow(M)/r)
nc <- ceiling(ncol(M)/c)
newM <- matrix(NA, nr*r, nc*c)
newM[1:nrow(M), 1:ncol(M)] <- M
div_k <- kronecker(matrix(seq_len(nr*nc), nr, byrow = TRUE), matrix(1, r, c))
matlist <- split(newM, div_k)
N <- length(matlist)
mats <- unlist(matlist)
dim(mats)<-c(r, c, N)
return(mats)
}
所以使用原始示例:
> M = matrix(sample(0:127,16*12,replace=TRUE), c(16,12))
> mat_split(M, 4, 3)
, , 1
[,1] [,2] [,3]
[1,] 107 45 107
[2,] 49 119 32
[3,] 79 114 26
[4,] 71 104 16
, , 2
[,1] [,2] [,3]
[1,] 79 77 4
[2,] 46 55 49
[3,] 122 15 0
[4,] 19 12 34
, , 3
[,1] [,2] [,3]
[1,] 114 28 74
[2,] 116 28 84
[3,] 80 49 95
[4,] 41 6 82
, , 4
[,1] [,2] [,3]
[1,] 17 17 13
[2,] 107 78 94
[3,] 22 16 14
[4,] 104 14 117
...
但如果你这样做:
mat_split(M,4,5)
你得到:
, , 1
[,1] [,2] [,3] [,4] [,5]
[1,] 107 45 107 79 77
[2,] 49 119 32 46 55
[3,] 79 114 26 122 15
[4,] 71 104 16 19 12
, , 2
[,1] [,2] [,3] [,4] [,5]
[1,] 4 114 28 74 17
[2,] 49 116 28 84 107
[3,] 0 80 49 95 22
[4,] 34 41 6 82 104
, , 3
[,1] [,2] [,3] [,4] [,5]
[1,] 17 13 NA NA NA
[2,] 78 94 NA NA NA
[3,] 16 14 NA NA NA
[4,] 14 117 NA NA NA
, , 4
[,1] [,2] [,3] [,4] [,5]
[1,] 112 56 20 54 68
[2,] 59 37 30 110 126
[3,] 34 22 110 13 73
[4,] 116 57 48 77 41
...
另一个有用的补充可能是选择输出作为矩阵列表而不是数组,这意味着您不必填充NA。
答案 2 :(得分:5)
使用expand.grid
回答,使用行和列列表进行拆分。可以推广使用不同大小的列/行块进行拆分。
M = matrix(sample(0:127,16*12,replace=TRUE), c(16,12))
split_matrix = function(M, list_of_rows,list_of_cols){
temp = expand.grid(list_of_rows,list_of_cols)
lapply(seq(nrow(temp)), function(i) {
M[unlist(temp[i,1]),unlist(temp[i,2]) ]
})
}
split_matrix(M,list(1:4,5:8,9:12,13:16),list(1:3,4:6,7:9,10:12))
答案 3 :(得分:4)
初始数据
M = matrix(sample(0:127,16*12,replace=TRUE), c(16,12))
> M
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
[1,] 46 46 64 54 48 78 125 38 103 43 15 125
[2,] 75 9 10 119 108 29 13 104 51 74 83 86
[3,] 52 22 97 12 44 115 118 111 114 56 31 36
[4,] 1 116 70 27 61 22 36 34 16 62 20 23
[5,] 32 61 11 46 34 120 50 71 44 105 52 81
[6,] 88 1 60 75 68 85 0 0 66 125 52 65
[7,] 119 32 75 14 119 57 74 107 21 32 110 39
[8,] 103 70 18 127 32 44 14 103 118 120 0 119
[9,] 12 99 0 48 31 126 92 78 9 11 52 21
[10,] 51 73 22 29 53 43 75 110 80 28 26 48
[11,] 64 5 81 127 25 59 50 21 46 87 66 122
[12,] 35 9 26 100 2 97 62 101 9 26 57 58
[13,] 90 16 70 118 122 120 50 125 26 34 54 55
[14,] 40 71 25 67 14 69 39 63 102 3 20 102
[15,] 51 66 92 19 7 53 33 123 50 78 83 111
[16,] 31 10 75 55 115 20 15 126 39 114 115 62
按列拆分
matrices_split_by_col = lapply(1:4, function(col){
M[,((col-1)*3+1):((col-1)*3+3)]
})
> matrices_split_by_col[[1]]
[,1] [,2] [,3]
[1,] 46 46 64
[2,] 75 9 10
[3,] 52 22 97
[4,] 1 116 70
[5,] 32 61 11
[6,] 88 1 60
[7,] 119 32 75
[8,] 103 70 18
[9,] 12 99 0
[10,] 51 73 22
[11,] 64 5 81
[12,] 35 9 26
[13,] 90 16 70
[14,] 40 71 25
[15,] 51 66 92
[16,] 31 10 75
现在做两个lapplies将每列拆分成行
matrices_split_by_row = lapply(matrices_split_by_col, function(mat){
lapply(1:4, function(row){
mat[((row-1)*3+1):((row-1)*3+4),]
})
})
取消结果:
matrices_split_by_row_and_col = unlist(matrices_split_by_row,recursive=FALSE)
检查结果:
> matrices_split_by_row_and_col[[2]]
[,1] [,2] [,3]
[1,] 1 116 70
[2,] 32 61 11
[3,] 88 1 60
[4,] 119 32 75
糟糕,这会让矩阵首先沿着列向下,但无论如何,您可以使用底层逻辑修改代码并将其转换为函数。
答案 4 :(得分:4)
修改@ MrFlick的答案:
matsplitter<-function(M, r, c) {
simplify2array(lapply(
split(M, interaction((row(M)-1)%/%r+1,(col(M)-1)%/%c+1)),
function(x) {dim(x) <- c(r,c); x;}
))
}
答案 5 :(得分:3)
使用我有限的常规编程知识,我想出了以下代码:
matsplitter = function(mat, submatr, submatc){
matr = dim(mat)[1]
matc = dim(mat)[2]
mats_per_row=matc/submatc
submat = array(NA, c(submatr,submatc,matr*matc/(submatr*submatc)))
cur_submat=1; k=0
i=j=a=b=1
while(TRUE){
submat[i,j,cur_submat+k] = mat[a,b]
j=j+1
if(j>submatc){j=1; k=k+1; if(k>(mats_per_row-1)){k=0; i=i+1; if(i>submatr){i=1;cur_submat=cur_submat+mats_per_row;}}}
b=b+1
if(b>matc){b=1;a=a+1; if(a>matr){break};}
}
submat
}
答案 6 :(得分:1)
这是使用split.data.frame
的另一种解决方案:
matsplitter <- function(M, r, c) {
splitMatrix <- function(mat, nrow) {
split.data.frame(t(mat), ceiling(1:ncol(mat)/ncol(mat)*nrow))
}
sapply(splitMatrix(M, c), splitMatrix, r)
}
然后该函数提供一个列表列表:
res <- matsplitter(M, 4, 3)
res
1 2 3
1 Integer,16 Integer,16 Integer,16
2 Integer,16 Integer,16 Integer,16
3 Integer,16 Integer,16 Integer,16
4 Integer,16 Integer,16 Integer,16
您可以子集所需矩阵的任何部分。例如第二行第二列块:
res[2,2]
[[1]]
[,1] [,2] [,3] [,4]
[1,] 116 93 73 53
[2,] 29 33 32 27
[3,] 29 57 89 96
[4,] 32 14 33 85
这适用于任何指定的尺寸,即使该数字不是行/列长度的倍数:
> matsplitter(M, 7, 7)
1 2 3 4 5 6 7
1 Integer,2 Integer,4 Integer,4 Integer,2 Integer,4 Integer,4 Integer,4
2 Integer,2 Integer,4 Integer,4 Integer,2 Integer,4 Integer,4 Integer,4
3 Integer,2 Integer,4 Integer,4 Integer,2 Integer,4 Integer,4 Integer,4
4 Integer,3 Integer,6 Integer,6 Integer,3 Integer,6 Integer,6 Integer,6
5 Integer,2 Integer,4 Integer,4 Integer,2 Integer,4 Integer,4 Integer,4
6 Integer,2 Integer,4 Integer,4 Integer,2 Integer,4 Integer,4 Integer,4
7 Integer,3 Integer,6 Integer,6 Integer,3 Integer,6 Integer,6 Integer,6