Reshape matrix by rows - r

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

Related

Bind dimensions of an array

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

How to automatically extract values from matrices

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

How to rearrange matrices?

I need to create a function, that will rearrange any square matrix based on the values in the matrix.
So if I have matrix like this:
M <- matrix(1:16, ncol = 4)
M
#> [,1] [,2] [,3] [,4]
#> [1,] 1 5 9 13
#> [2,] 2 6 10 14
#> [3,] 3 7 11 15
#> [4,] 4 8 12 16
After rearrangement it needs to look like this:
[,1] [,2] [,3] [,4]
[1,] 1 3 6 10
[2,] 2 5 9 13
[3,] 4 8 12 15
[4,] 7 11 14 16
So it is sorted from lowest (left upper corner) to highest (right lower corner), but the numbers are sorted on diagonal (is that the right word?) not in rows or columns.
I know how to to this "manually", but I can't figure out any rules that this rearrangement operates by.
1) row(m) + col(m) is constant along reverse diagonals so:
M <- replace(m, order(row(m) + col(m)), m)
gving:
> M
[,1] [,2] [,3] [,4]
[1,] 1 3 6 10
[2,] 2 5 9 13
[3,] 4 8 12 15
[4,] 7 11 14 16
It is not clear whether sorted on the diagonal means just that they are unravelled from the storage order onto the reverse diagonals or that they are actually sorted after that within each reverse diagonal. In the example in the question the two interpretations give the same answer; however, if you did wish to sort the result within reverse diagonal afterwards using different data then apply this:
ave(M, row(M) + col(M), FUN = sort)
2) A longer version:
M2 <- matrix(m[order(unlist(tapply(seq_along(m), row(m) + col(m), c)))], nrow(m))
Here's a function columns_to_diagonals in base R that ought to do what you're after. It uses split and unsplit with the appropriate factors.
columns_to_diagonals <- function(M) {
n <- ncol(M)
f <- matrix(rep(1:(2*n-1), c(1:n, (n-1):1)), ncol = n)
m <- split(M, f)
d <- row(M) + col(M)
matrix(unsplit(m, d), ncol = n)
}
First, we may test this on your original case:
M <- matrix(1:16, ncol = 4)
columns_to_diagonals(M)
#> [,1] [,2] [,3] [,4]
#> [1,] 1 3 6 10
#> [2,] 2 5 9 13
#> [3,] 4 8 12 15
#> [4,] 7 11 14 16
And then a larger, randomly permutated matrix, to check that this looks fine as well:
M <- matrix(sample(1:25), ncol = 5)
M
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 4 15 12 10 21
#> [2,] 19 7 5 23 6
#> [3,] 9 17 2 8 1
#> [4,] 3 11 16 25 14
#> [5,] 22 18 20 13 24
columns_to_diagonals(M)
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 4 9 15 18 20
#> [2,] 19 22 11 16 25
#> [3,] 3 17 2 8 6
#> [4,] 7 5 23 21 14
#> [5,] 12 10 13 1 24
Created on 2019-12-15 by the reprex package (v0.2.1)

Multiply elements of a matrix with vector values

I have a matrix M, I want to create 3 additional matrices where each additional matrix has certain 3x3 column-slices of M multiplied by values in a vector, I will then store the resulting 3 new matrices in a list.
##create the initial matrix
M <- matrix(1:20, nrow = 4)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 5 9 13 17
[2,] 2 6 10 14 18
[3,] 3 7 11 15 19
[4,] 4 8 12 16 20
## coordinates in the matrix I want to alter
iy <- c(1, 2, 3)
ix <- c(1, 4, 5)
coords <- as.data.frame(cbind(ix, iy))
## multiplier values
multis <- c(0.1, 2, 100)
Pseudo code of what I want to do
mapply (function(multis, cords) {multis * M[coords$iy, coords$ix]})
what the result should look like
[[1]]
[,1] [,2] [,3] [,4] [,5]
[1,] 0.1 5 9 13.0 17.0
[2,] 2.0 6 10 1.4 18.0
[3,] 3.0 7 11 15.0 1.1
[4,] 4.0 8 12 16.0 20.0
[[2]]
[,1] [,2] [,3] [,4] [,5]
[1,] 2 5 9 13 17
[2,] 2 6 10 28 18
[3,] 3 7 11 15 38
[4,] 4 8 12 16 20
[[3]]
[,1] [,2] [,3] [,4] [,5]
[1,] 100 5 9 13 17
[2,] 2 6 10 1400 18
[3,] 3 7 11 15 1900
[4,] 4 8 12 16 20
First you need to coerce coords to a matrix for indexing, then reverse the column order. Then it's just a simple lapply() loop.
coords <- as.matrix(coords)[, 2:1]
lapply(multis, function(x) {
M[coords] <- M[coords] * x
M
})
resulting in
[[1]]
[,1] [,2] [,3] [,4] [,5]
[1,] 0.1 5 9 13.0 17.0
[2,] 2.0 6 10 1.4 18.0
[3,] 3.0 7 11 15.0 1.9
[4,] 4.0 8 12 16.0 20.0
[[2]]
[,1] [,2] [,3] [,4] [,5]
[1,] 2 5 9 13 17
[2,] 2 6 10 28 18
[3,] 3 7 11 15 38
[4,] 4 8 12 16 20
[[3]]
[,1] [,2] [,3] [,4] [,5]
[1,] 100 5 9 13 17
[2,] 2 6 10 1400 18
[3,] 3 7 11 15 1900
[4,] 4 8 12 16 20
Another solution is to use a defined function and use a sapply for each multis:
##create the initial matrix
M <- matrix(1:20, nrow = 4)
## coordinates in the matrix I want to alter
Y <- c(1, 2, 3)
X <- c(1, 4, 5)
coords <- as.data.frame(cbind(X, Y))
## multiplier values
multis <- c(0.1, 2, 100)
## Modifying the specific coordinates.
modif.one.matrix <- function(one_multis, coords, M) {
M_out <- M
for(one_coord in 1:nrow(coords)) {
M_out[coords$Y[one_coord], coords$X[one_coord]] <- M[coords$Y[one_coord], coords$X[one_coord]] * one_multis
}
return(M_out)
}
## Modifying one matrix
modif.one.matrix(multis[1], coords, M)
# [,1] [,2] [,3] [,4] [,5]
#[1,] 0.1 5 9 13.0 17.0
#[2,] 2.0 6 10 1.4 18.0
#[3,] 3.0 7 11 15.0 1.9
#[4,] 4.0 8 12 16.0 20.0
## Modifying all the matrices
sapply(multis, modif.one.matrix, coords, M, simplify = FALSE)
#[[1]]
# [,1] [,2] [,3] [,4] [,5]
#[1,] 0.1 5 9 13.0 17.0
#[2,] 2.0 6 10 1.4 18.0
#[3,] 3.0 7 11 15.0 1.9
#[4,] 4.0 8 12 16.0 20.0
#
#[[2]]
# [,1] [,2] [,3] [,4] [,5]
#[1,] 2 5 9 13 17
#[2,] 2 6 10 28 18
#[3,] 3 7 11 15 38
#[4,] 4 8 12 16 20
#
#[[3]]
# [,1] [,2] [,3] [,4] [,5]
#[1,] 100 5 9 13 17
#[2,] 2 6 10 1400 18
#[3,] 3 7 11 15 1900
#[4,] 4 8 12 16 20

Replicate rows of a matrix in R

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

Resources