I have a matrix M with 16 rows and 12 columns and I want to split it into a array of 16 matrices, each with 4 rows and 3 columns. I can do it manually by:
我有一个矩阵M,有16行和12列,我想把它分成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]
.....
But how can I create a generic function matsplitter(M, r, c) which splits M into an array of matrices, each with r rows and c columns?
但是,我如何创建一个通用的功能分配器(M, r, c),它将M分割成一个矩阵数组,每个矩阵都有r行和c列?
Thanks for your help.
谢谢你的帮助。
6 个解决方案
#1
13
If you have a 16x12 array like this
如果你有一个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))
You can define matsplitter
as
您可以将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
}
Then
然后
matsplitter(mb,4,3)
will return (output clipped)
将返回(输出剪)
, , 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"
...
#2
6
Here is a function that uses Kronecker products to do the same thing. Why? Because I enjoy Kronecker products. The bonus here is that if your row and column values don't divide evenly into your input matrix then this function will pad out the smaller matrices at the right and bottom edges with NAs so you can still have an array output.
这里有一个函数使用Kronecker产品做同样的事情。为什么?因为我喜欢克罗内克的产品。这里的好处是,如果你的行和列值不均匀地分配到你的输入矩阵中,那么这个函数将会在右边和底部边缘用NAs填充较小的矩阵,这样你仍然可以有一个数组输出。
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)
}
So using the original example:
所以,使用最初的例子:
> 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
...
but if you do this:
但如果你这样做:
mat_split(M, 4, 5)
mat_split(M,4、5)
you get:
你会得到:
, , 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
...
Another useful addition might be to have the option to output as a list of matrices, instead of an array, which means you wouldn't have to pad with NAs.
另一个有用的补充可能是将选项输出为矩阵列表,而不是数组,这意味着您不必使用NAs。
#3
3
Answer using expand.grid
, using a list of rows and columns to split by. Can generalise to splitting by differently sized column/row blocks.
回答使用扩展。网格,使用一个行和列的列表来分隔。可以通过不同大小的列/行块进行划分。
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))
#4
2
Initial data
初始数据
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
Split by columns
拆分的列
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
Now do two lapplies to split each column into rows
现在执行两个lapply将每个列分割成行。
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),]
})
})
Unlist the result:
Unlist结果:
matrices_split_by_row_and_col = unlist(matrices_split_by_row,recursive=FALSE)
Check result:
检查结果:
> 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
Oops, this gives the matrices going down the columns first, but anyway, you can modify the code and turn it into a function if you want, using the underlying logic.
噢,这让矩阵先从列开始,但不管怎样,你可以修改代码,如果你想,可以把它转换成一个函数,使用底层逻辑。
#5
2
Using my limited regular programming knowledge, I came up with following code:
利用有限的常规编程知识,我提出了以下代码:
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
Modification of @MrFlick's answer:
修改@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;}
))
}
#1
13
If you have a 16x12 array like this
如果你有一个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))
You can define matsplitter
as
您可以将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
}
Then
然后
matsplitter(mb,4,3)
will return (output clipped)
将返回(输出剪)
, , 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"
...
#2
6
Here is a function that uses Kronecker products to do the same thing. Why? Because I enjoy Kronecker products. The bonus here is that if your row and column values don't divide evenly into your input matrix then this function will pad out the smaller matrices at the right and bottom edges with NAs so you can still have an array output.
这里有一个函数使用Kronecker产品做同样的事情。为什么?因为我喜欢克罗内克的产品。这里的好处是,如果你的行和列值不均匀地分配到你的输入矩阵中,那么这个函数将会在右边和底部边缘用NAs填充较小的矩阵,这样你仍然可以有一个数组输出。
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)
}
So using the original example:
所以,使用最初的例子:
> 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
...
but if you do this:
但如果你这样做:
mat_split(M, 4, 5)
mat_split(M,4、5)
you get:
你会得到:
, , 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
...
Another useful addition might be to have the option to output as a list of matrices, instead of an array, which means you wouldn't have to pad with NAs.
另一个有用的补充可能是将选项输出为矩阵列表,而不是数组,这意味着您不必使用NAs。
#3
3
Answer using expand.grid
, using a list of rows and columns to split by. Can generalise to splitting by differently sized column/row blocks.
回答使用扩展。网格,使用一个行和列的列表来分隔。可以通过不同大小的列/行块进行划分。
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))
#4
2
Initial data
初始数据
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
Split by columns
拆分的列
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
Now do two lapplies to split each column into rows
现在执行两个lapply将每个列分割成行。
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),]
})
})
Unlist the result:
Unlist结果:
matrices_split_by_row_and_col = unlist(matrices_split_by_row,recursive=FALSE)
Check result:
检查结果:
> 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
Oops, this gives the matrices going down the columns first, but anyway, you can modify the code and turn it into a function if you want, using the underlying logic.
噢,这让矩阵先从列开始,但不管怎样,你可以修改代码,如果你想,可以把它转换成一个函数,使用底层逻辑。
#5
2
Using my limited regular programming knowledge, I came up with following code:
利用有限的常规编程知识,我提出了以下代码:
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
Modification of @MrFlick's answer:
修改@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;}
))
}