Let's start with an exemplary multi-dimensional array like
a <- array(1:24, dim = c(3, 2, 2, 2)); a
, , 1, 1
[,1] [,2]
[1,] 1 4
[2,] 2 5
[3,] 3 6
, , 2, 1
[,1] [,2]
[1,] 7 10
[2,] 8 11
[3,] 9 12
, , 1, 2
[,1] [,2]
[1,] 13 16
[2,] 14 17
[3,] 15 18
, , 2, 2
[,1] [,2]
[1,] 19 22
[2,] 20 23
[3,] 21 24
Now I want to cbind or rbind the first two dimensions, which are matrices over the remaining dimensions 3 and 4, to an entire data.frame.
The resulting data.frame should like this using rbind:
[,1] [,2]
[1, ] 1 4
[2, ] 2 5
[3, ] 3 6
[4, ] 7 10
[5, ] 8 11
[6, ] 9 12
...
What would be an efficient way to bind the first two dimensions of a multi-dimensional array to an entire structure like data.frame? Please consider that the array can have any number of dimensions greater than 2, and not only 4 like in the above given example.
Thanks in advance
You can use apply:
apply(a, 2, identity)
# [,1] [,2]
# [1,] 1 4
# [2,] 2 5
# [3,] 3 6
# [4,] 7 10
# [5,] 8 11
# [6,] 9 12
# [7,] 13 16
# [8,] 14 17
# [9,] 15 18
#[10,] 19 22
#[11,] 20 23
#[12,] 21 24
Permuting and modifying dimensions is quite efficient:
a <- array(1:24, dim = c(3, 2, 2, 2))
a <- aperm(a, c(2, 1, 3, 4))
dim(a) <- c(dim(a)[1], prod(dim(a)[-1]))
t(a)
# [,1] [,2]
# [1,] 1 4
# [2,] 2 5
# [3,] 3 6
# [4,] 7 10
# [5,] 8 11
# [6,] 9 12
# [7,] 13 16
# [8,] 14 17
# [9,] 15 18
#[10,] 19 22
#[11,] 20 23
#[12,] 21 24
Related
I have a list of matrices where most of the matrices are column matrices but some of them are row matrices. How to convert only those row matrices to column matrices? I would like to achieve this using base R.
Here is the list of matrices where the third one is a row matrix
x <- list(`1` = matrix(1:20, nrow=5), `2` = matrix(1:20, nrow=10), `3` = matrix(1:5, nrow=1))
How to convert the list to one like this:
$`1`
[,1] [,2] [,3] [,4] [,5]
[1,] 1 3 5 7 9
[2,] 2 4 6 8 10
$`2`
[,1] [,2]
[1,] 1 6
[2,] 2 7
[3,] 3 8
[4,] 4 9
[5,] 5 10
$`3`
[1,] 1
[2,] 2
[3,] 3
[4,] 4
[5,] 5
I have a much larger dataset and so efficient code is preferred!
Check the dimensions of the matrix and transpose it if the row dimension is 1:
(y <- lapply(x, function(x) if(dim(x)[1] == 1) { t(x)} else x))
# $`1`
# [,1] [,2] [,3] [,4]
# [1,] 1 6 11 16
# [2,] 2 7 12 17
# [3,] 3 8 13 18
# [4,] 4 9 14 19
# [5,] 5 10 15 20
#
# $`2`
# [,1] [,2]
# [1,] 1 11
# [2,] 2 12
# [3,] 3 13
# [4,] 4 14
# [5,] 5 15
# [6,] 6 16
# [7,] 7 17
# [8,] 8 18
# [9,] 9 19
# [10,] 10 20
#
# $`3`
# [,1]
# [1,] 1
# [2,] 2
# [3,] 3
# [4,] 4
# [5,] 5
I am a newbie in R, I now have a matrix of 3 columns and 8, 000 rows, with groups of 500 rows, which means 16 sets of 500*3 matrices stacked on top of each other in rows. Now I want to take the first 300 rows of each group of matrices, put 16 groups of 300 by 3 into a new matrix, what do I do?
Two 6 * 2 matrices on top of each other:
m <- matrix(1:24, ncol = 2)
# [,1] [,2]
# [1,] 1 13
# [2,] 2 14
# [3,] 3 15
# [4,] 4 16
# [5,] 5 17
# [6,] 6 18
# [7,] 7 19
# [8,] 8 20
# [9,] 9 21
#[10,] 10 22
#[11,] 11 23
#[12,] 12 24
Make it an array:
a <- array(m, c(6, 2, 2))
a <- aperm(a, c(1, 3, 2))
First three rows of each matrix:
a[1:3,,]
#, , 1
#
# [,1] [,2]
#[1,] 1 13
#[2,] 2 14
#[3,] 3 15
#
#, , 2
#
# [,1] [,2]
#[1,] 7 19
#[2,] 8 20
#[3,] 9 21
Use this if you need a matrix:
matrix(aperm(a[1:3,,], c(1, 3, 2)), ncol = 2)
# [,1] [,2]
#[1,] 1 13
#[2,] 2 14
#[3,] 3 15
#[4,] 7 19
#[5,] 8 20
#[6,] 9 21
You need to generate the sequence 1:300, 501:800, ... etc, then subset out these rows. If your matrix is called mat you can do that like this:
new_mat <- mat[as.numeric(sapply((0:15 * 500), "+", 1:300)),]
If you're looking for just a way to select the first 300 rows from your matrix for each group, this could be a solution.
Given m your matrix of 8000x3 composed by 16 groups on top of each other, then:
r <- 500 # rows for each group
g <- 16 # number of groups
n <- 300 # first n rows to select
new_m <- m[rep(rep(c(T,F), c(n,r-n)), g), ]
dim(new_m)
#> [1] 4800 3
new_m is now a matrix 4800x3
In case you are working with keras or reticulate, you could use array_reshape.
#### 0. parameters
nrows <- 4 # 500 in your example # rows for each group
ncols <- 3 # 3 in your example
ngrps <- 2 # 16 in your example # number of groups
nslct <- 3 # 300 in your example # first n rows to select
#### 1. create an example matrix
m <- matrix(1:24, nrows*ngrps, ncols)
m
#> [,1] [,2] [,3]
#> [1,] 1 9 17
#> [2,] 2 10 18
#> [3,] 3 11 19
#> [4,] 4 12 20
#> [5,] 5 13 21
#> [6,] 6 14 22
#> [7,] 7 15 23
#> [8,] 8 16 24
dim(m)
#> [1] 8 3
#--> c(ngrps * nrows, ncols)
#### 2. reshape in groups
m <- reticulate::array_reshape(m, c(ngrps,nrows,ncols))
dim(m)
#> [1] 2 4 3
# --> c(n_groups, n_rows, n_cols)
m[1,,]
#> [,1] [,2] [,3]
#> [1,] 1 9 17
#> [2,] 2 10 18
#> [3,] 3 11 19
#> [4,] 4 12 20
m[2,,]
#> [,1] [,2] [,3]
#> [1,] 5 13 21
#> [2,] 6 14 22
#> [3,] 7 15 23
#> [4,] 8 16 24
#### 3. select first nslct rows for each group
new_m <- m[,seq_len(nslct),]
# that's the result for each group
new_m[1,,]
#> [,1] [,2] [,3]
#> [1,] 1 9 17
#> [2,] 2 10 18
#> [3,] 3 11 19
new_m[2,,]
#> [,1] [,2] [,3]
#> [1,] 5 13 21
#> [2,] 6 14 22
#> [3,] 7 15 23
#### 4. recreate one matrix
reticulate::array_reshape(new_m, c(nslct*ngrps,ncols))
#> [,1] [,2] [,3]
#> [1,] 1 9 17
#> [2,] 2 10 18
#> [3,] 3 11 19
#> [4,] 5 13 21
#> [5,] 6 14 22
#> [6,] 7 15 23
Created on 2020-11-23 by the reprex package (v0.3.0)
A simple way to generate an array that mimics the fill of your matrix is to use the transpose of the matrix as the input for the array function. Here is a simple example:
n <- rep(1:3, each = 4)
m1 <- matrix(n, ncol = 2, byrow = TRUE)
> m1
[,1] [,2]
[1,] 1 1
[2,] 1 1
[3,] 2 2
[4,] 2 2
[5,] 3 3
[6,] 3 3
m2 <- t(m1)
a1 <- array(m2, c(2, 2, 3))
> a1
, , 1
[,1] [,2]
[1,] 1 1
[2,] 1 1
, , 2
[,1] [,2]
[1,] 2 2
[2,] 2 2
, , 3
[,1] [,2]
[1,] 3 3
[2,] 3 3
I have a matrix with size 18000 x 54. I would like to reshape it as a matrix with size 54000 x 18, in which each row of my initial matrix becomes a matrix which has 3 rows.
Let's take an example. I have a matrix as follow:
a = matrix(1:18, nrow = 2, ncol = 9, byrow = T)
a
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18
I would like to reshape this matrix so that it becomes:
[,1] [,2] [,3]
1 4 7
2 5 8
3 6 9
10 13 16
11 14 17
12 15 18
I tried two following ways, but they do not work. The first is as follows:
dim(a) = c(6,3)
The second one is to create a function and then apply to each row:
reshapeX = function(x){
dim(x) = c(3,as.integer(length(x)/3))
return(as.matrix(x))
}
rbind(apply(a, 1, reshapeX))
But it does not work neither. Can someone help please?
You can do:
do.call(rbind, lapply(1:nrow(a), function(i) matrix(a[i, ], nrow=3)))
with your data:
a <- matrix(1:18, nrow = 2, ncol = 9, byrow = TRUE)
do.call(rbind, lapply(1:nrow(a), function(i) matrix(a[i, ], nrow=3)))
# [,1] [,2] [,3]
# [1,] 1 4 7
# [2,] 2 5 8
# [3,] 3 6 9
# [4,] 10 13 16
# [5,] 11 14 17
# [6,] 12 15 18
Here is a loop free method,
m1 <- matrix(c(a), ncol = 3, nrow = 6)
rbind(m1[c(TRUE, FALSE),], m1[c(FALSE, TRUE),])
# [,1] [,2] [,3]
#[1,] 1 4 7
#[2,] 2 5 8
#[3,] 3 6 9
#[4,] 10 13 16
#[5,] 11 14 17
#[6,] 12 15 18
An option would be
out <- sapply(split.default(as.data.frame(a), as.integer(gl(ncol(a), 3,
ncol(a)))), function(x) c(t(x)))
colnames(out) <- NULL
out
# [,1] [,2] [,3]
#[1,] 1 4 7
#[2,] 2 5 8
#[3,] 3 6 9
#[4,] 10 13 16
#[5,] 11 14 17
#[6,] 12 15 18
Or in shorter form of the above
sapply(split(a,(col(a)-1) %/%3), function(x) c(matrix(x, nrow = 3, byrow = TRUE)))
Or this can be done more compactly with array
apply(array(c(t(a)), c(3, 3, 2)), 2, c)
# [,1] [,2] [,3]
#[1,] 1 4 7
#[2,] 2 5 8
#[3,] 3 6 9
#[4,] 10 13 16
#[5,] 11 14 17
#[6,] 12 15 18
I want to iterate the following matrix and print sets of 2 cell values. Is there a way to do this without a for-loop?
Input:
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 4 7 10 13 16
[2,] 2 5 8 11 14 17
[3,] 3 6 9 12 15 18
Expected Output:
[,1] [,2]
[1,] 1 4
[2,] 7 10
[3,] 13 16
[4,] 2 5
[5,] 8 11
[6,] 14 17
[7,] 3 6
[8,] 9 12
[9,] 15 18
This my code:
mat<-matrix(data=seq(1:18), nrow=3,ncol=6)
r <- rep(seq(1,3),each=2)
c1 <- seq(1,6,2)
c2 <- seq(2,6,2)
m <- mat[r,c(c1:c2)] # This does not work, it only output first two cells
We can get the transpose of the matrix, then convert back to matrix by specifying the ncol
matrix(t(mat), ncol=2, byrow=TRUE)
# [,1] [,2]
# [1,] 1 4
# [2,] 7 10
# [3,] 13 16
# [4,] 2 5
# [5,] 8 11
# [6,] 14 17
# [7,] 3 6
# [8,] 9 12
# [9,] 15 18
Suppose I have a matrix m and a positive integer vector v, what I want to do is get a new matrix m_new and each row of m (say m[i, ]) are replicated by v[i] times in m_new. For example:
m = matrix(1:6, nrow = 3)
## [,1] [,2]
## [1,] 1 4
## [2,] 2 5
## [3,] 3 6
v = c(3, 1, 2)
And m_new should be:
[,1] [,2]
[1,] 1 4 # m[1, ] is replicated by
[2,] 1 4 # v[1] = 3
[3,] 1 4 # times
[4,] 2 5
[5,] 3 6
[6,] 3 6
A for loop will make it for the small case:
m_new = matrix(0, sum(v), ncol(m))
k = 1
for(i in 1:nrow(m)){
for(j in k:(k+v[i]-1)){
m_new[j, ] = m[i, ]
}
k = k + v[i]
}
, but the row number of m in real world is usually big. Is there any effient way to do this?
m[rep(1:nrow(m), times = v), ]
# [,1] [,2]
# [1,] 1 4
# [2,] 1 4
# [3,] 1 4
# [4,] 2 5
# [5,] 3 6
# [6,] 3 6
> m <- matrix(1:25, ncol=5)
> m
[,1] [,2] [,3] [,4] [,5]
[1,] 1 6 11 16 21
[2,] 2 7 12 17 22
[3,] 3 8 13 18 23
[4,] 4 9 14 19 24
[5,] 5 10 15 20 25
> apply(m, 2, function(c) rep(c,v))
[,1] [,2] [,3] [,4] [,5]
[1,] 1 6 11 16 21
[2,] 2 7 12 17 22
[3,] 2 7 12 17 22
[4,] 3 8 13 18 23
[5,] 3 8 13 18 23
[6,] 3 8 13 18 23
[7,] 4 9 14 19 24
[8,] 4 9 14 19 24
[9,] 4 9 14 19 24
[10,] 4 9 14 19 24
[11,] 5 10 15 20 25
[12,] 5 10 15 20 25
[13,] 5 10 15 20 25
[14,] 5 10 15 20 25
[15,] 5 10 15 20 25