Transforming a table in a 3D array in R - r

I have a matrix:
R> pippo.m
[,1] [,2] [,3] [,4]
[1,] 1 2 3 4
[2,] 5 6 7 8
[3,] 9 10 11 12
[4,] 13 14 15 16
[5,] 17 18 19 20
[6,] 21 22 23 24
and I would like to transform this matrix in a 3D array with dim=(2,4,3). Passing through the transponse of pippo.m I am able to obtain a similar result but with columns and rows rotated.
> pippo.t <- t(pippo.m)
> pippo.vec <- as.vector(pippo.t)
> pippo.arr <- array(pippo.vec,dim=c(4,2,3),dimnames=NULL)
> pippo.arr
, , 1
[,1] [,2]
[1,] 1 5
[2,] 2 6
[3,] 3 7
[4,] 4 8
, , 2
[,1] [,2]
[1,] 9 13
[2,] 10 14
[3,] 11 15
[4,] 12 16
, , 3
[,1] [,2]
[1,] 17 21
[2,] 18 22
[3,] 19 23
[4,] 20 24
Actually, I would prefer to mantain the same distribution of the original data, as rows and colums represent longitude and latitude and the third dimension is time. So I would like to obtain something like this:
pippo.a
, , 1
[,1] [,2] [,3] [,4]
[1,] 1 2 3 4
[2,] 5 6 7 8
, , 2
[,1] [,2] [,3] [,4]
[1,] 9 10 11 12
[2,] 13 14 15 16
, , 3
[,1] [,2] [,3] [,4]
[1,] 17 18 19 20
[2,] 21 22 23 24
How can I do?

Behold the magic of aperm!
m <- matrix(1:24,6,4,byrow = TRUE)
> aperm(array(t(m),c(4,2,3)),c(2,1,3))
, , 1
[,1] [,2] [,3] [,4]
[1,] 1 2 3 4
[2,] 5 6 7 8
, , 2
[,1] [,2] [,3] [,4]
[1,] 9 10 11 12
[2,] 13 14 15 16
, , 3
[,1] [,2] [,3] [,4]
[1,] 17 18 19 20
[2,] 21 22 23 24

Related

Switch rows between two matrices in R

Let the matrices A and B.
A=c(1:5)*matrix(1,5,5)
B=10*A
that is,
> A
[,1] [,2] [,3] [,4] [,5]
[1,] 1 1 1 1 1
[2,] 2 2 2 2 2
[3,] 3 3 3 3 3
[4,] 4 4 4 4 4
[5,] 5 5 5 5 5
> B
[,1] [,2] [,3] [,4] [,5]
[1,] 10 10 10 10 10
[2,] 20 20 20 20 20
[3,] 30 30 30 30 30
[4,] 40 40 40 40 40
[5,] 50 50 50 50 50
I would like, for example, to switch the first rows between the matrices A and B, that is
> A
[,1] [,2] [,3] [,4] [,5]
[1,] 10 10 10 10 10
[2,] 2 2 2 2 2
[3,] 3 3 3 3 3
[4,] 4 4 4 4 4
[5,] 5 5 5 5 5
> B
[,1] [,2] [,3] [,4] [,5]
[1,] 1 1 1 1 1
[2,] 20 20 20 20 20
[3,] 30 30 30 30 30
[4,] 40 40 40 40 40
[5,] 50 50 50 50 50
using a function, and without using any indermediate vector or a for loop.
Update
As per you update in the comment, you can try
lapply(
1:nrow(B),
function(k) {
setNames(
Map(
function(x, ind,r) {
x[ind, ] <- r
x
},
list(A, B),
list(1,k),
list(B[k, ], A[1, ])
), c("A", "B")
)
}
)
which gives
[[1]]
[[1]]$A
[,1] [,2] [,3] [,4] [,5]
[1,] 10 10 10 10 10
[2,] 2 2 2 2 2
[3,] 3 3 3 3 3
[4,] 4 4 4 4 4
[5,] 5 5 5 5 5
[[1]]$B
[,1] [,2] [,3] [,4] [,5]
[1,] 1 1 1 1 1
[2,] 20 20 20 20 20
[3,] 30 30 30 30 30
[4,] 40 40 40 40 40
[5,] 50 50 50 50 50
[[2]]
[[2]]$A
[,1] [,2] [,3] [,4] [,5]
[1,] 20 20 20 20 20
[2,] 2 2 2 2 2
[3,] 3 3 3 3 3
[4,] 4 4 4 4 4
[5,] 5 5 5 5 5
[[2]]$B
[,1] [,2] [,3] [,4] [,5]
[1,] 10 10 10 10 10
[2,] 1 1 1 1 1
[3,] 30 30 30 30 30
[4,] 40 40 40 40 40
[5,] 50 50 50 50 50
[[3]]
[[3]]$A
[,1] [,2] [,3] [,4] [,5]
[1,] 30 30 30 30 30
[2,] 2 2 2 2 2
[3,] 3 3 3 3 3
[4,] 4 4 4 4 4
[5,] 5 5 5 5 5
[[3]]$B
[,1] [,2] [,3] [,4] [,5]
[1,] 10 10 10 10 10
[2,] 20 20 20 20 20
[3,] 1 1 1 1 1
[4,] 40 40 40 40 40
[5,] 50 50 50 50 50
[[4]]
[[4]]$A
[,1] [,2] [,3] [,4] [,5]
[1,] 40 40 40 40 40
[2,] 2 2 2 2 2
[3,] 3 3 3 3 3
[4,] 4 4 4 4 4
[5,] 5 5 5 5 5
[[4]]$B
[,1] [,2] [,3] [,4] [,5]
[1,] 10 10 10 10 10
[2,] 20 20 20 20 20
[3,] 30 30 30 30 30
[4,] 1 1 1 1 1
[5,] 50 50 50 50 50
[[5]]
[[5]]$A
[,1] [,2] [,3] [,4] [,5]
[1,] 50 50 50 50 50
[2,] 2 2 2 2 2
[3,] 3 3 3 3 3
[4,] 4 4 4 4 4
[5,] 5 5 5 5 5
[[5]]$B
[,1] [,2] [,3] [,4] [,5]
[1,] 10 10 10 10 10
[2,] 20 20 20 20 20
[3,] 30 30 30 30 30
[4,] 40 40 40 40 40
[5,] 1 1 1 1 1
You can try the code below
list2env(
setNames(
Map(
function(x, r) {
x[1, ] <- r
x
},
list(A, B),
list(B[1, ], A[1, ])
), c("A", "B")
),
envir = .GlobalEnv
)
replace seems to work without any intermediate
replace(A, cbind(1, 1:ncol(A)), B[1,])
replace(B, cbind(1, 1:ncol(A)), A[1,])
Note that once we do the assignment to the original object, the second assignment is not possible as the original object is changed
A clean way to swap is to create a temporary object and rm it
tmp <- A[1,]
A[1, ] <- B[1, ]
B[1, ] <- tmp
rm(tmp)
gc()
Or probably create a function, and do the swap inside the function, thus the activation record is deleted once it exit the function (as these are pass by value)
f1 <- function(a, b) {
t1 <- a[1,]
a[1,] <- b[1,]
b[1,] <- t1
return(list(a, b))
}
list2env(setNames(f1(A, B), c('A', 'B')), .GlobalEnv)

How to multiply a matrix by a known vector to return an array

Good afternoon!
Assume we have a vector and a matrix :
v = c(2,3,4)
[1] 2 3 4
m=matrix(1:9,ncol=3)
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
I'm searching an efficient way ( or built-in function ) to get three matrices m1 , m2 , m3 such that :
m1=v[1]*m
m2=v[2]*m
m3=v[3]*m
We could obtain this using a 3d-array :
my_fct<-function(m,v){
f=array(data=rep(NA,nrow(m)*ncol(m)*length(v)),dim = c(nrow(m),ncol(m),length(v)))
for (j in c(1:length(v))){
f[,,j]=v[j]*m
}
return(f)
}
my_fct(m,v)
, , 1
[,1] [,2] [,3]
[1,] 2 8 14
[2,] 4 10 16
[3,] 6 12 18
, , 2
[,1] [,2] [,3]
[1,] 3 12 21
[2,] 6 15 24
[3,] 9 18 27
, , 3
[,1] [,2] [,3]
[1,] 4 16 28
[2,] 8 20 32
[3,] 12 24 36
I hope my request is clear!
Thank you a lot for help !
As 'v' is a vector and we want each element to be multiplied by the same matrix 'm', an option is to loop over the element of 'v' and do the multiplication
lapply(v, `*`, m)
-output
[[1]]
[,1] [,2] [,3]
[1,] 2 8 14
[2,] 4 10 16
[3,] 6 12 18
[[2]]
[,1] [,2] [,3]
[1,] 3 12 21
[2,] 6 15 24
[3,] 9 18 27
[[3]]
[,1] [,2] [,3]
[1,] 4 16 28
[2,] 8 20 32
[3,] 12 24 36
Another base R option
> Map(`*`, list(m), v)
[[1]]
[,1] [,2] [,3]
[1,] 2 8 14
[2,] 4 10 16
[3,] 6 12 18
[[2]]
[,1] [,2] [,3]
[1,] 3 12 21
[2,] 6 15 24
[3,] 9 18 27
[[3]]
[,1] [,2] [,3]
[1,] 4 16 28
[2,] 8 20 32
[3,] 12 24 36

creating a matrix with a nested for loop

This is a practice question to prep for an exam. I'm given the following code:
W=matrix(1:16,byrow=T,ncol=4)
print(W)
fmat=function(W){
n=nrow(W)
for (i in 1:n){
for (j in 1:n){
W[j,i]=W[i,j]+W[j,i]
}
}
return(W)
}
print(fmat(W))
We have to "run" the code on paper and then check our answers by running the code in R. I wrote out the correct matrix for W but I got fmat(W) wrong. R gives me the following output for fmat(W):
[,1] [,2] [,3] [,4]
[1,] 2 9 15 21
[2,] 7 12 24 30
[3,] 12 17 22 39
[4,] 17 22 27 32
where I had written down that fmat(W) would equal:
[,1] [,2] [,3] [,4]
[1,] 2 7 12 17
[2,] 7 12 17 22
[3,] 12 17 22 27
[4,] 17 22 27 32
What exactly is going on here? I had interpreted the function to calculate that, for example, w[2,1]=w[1,2]+w[2,1], which is 2+5=7.
In you code, W is overwritten in your nested for loop by columns and then by rows.
To visualize the progress, you can add print(W) before your value assignment W[j,i] = W[i,j]+W[j,i], i.e.,
fmat=function(W){
n=nrow(W)
for (i in 1:n){
for (j in 1:n){
print(W)
W[j,i]=W[i,j]+W[j,i]
}
}
return(W)
}
such that
> fmat(W)
[,1] [,2] [,3] [,4]
[1,] 1 2 3 4
[2,] 5 6 7 8
[3,] 9 10 11 12
[4,] 13 14 15 16
[,1] [,2] [,3] [,4]
[1,] 2 2 3 4
[2,] 5 6 7 8
[3,] 9 10 11 12
[4,] 13 14 15 16
[,1] [,2] [,3] [,4]
[1,] 2 2 3 4
[2,] 7 6 7 8
[3,] 9 10 11 12
[4,] 13 14 15 16
[,1] [,2] [,3] [,4]
[1,] 2 2 3 4
[2,] 7 6 7 8
[3,] 12 10 11 12
[4,] 13 14 15 16
[,1] [,2] [,3] [,4]
[1,] 2 2 3 4
[2,] 7 6 7 8
[3,] 12 10 11 12
[4,] 17 14 15 16
[,1] [,2] [,3] [,4]
[1,] 2 9 3 4
[2,] 7 6 7 8
[3,] 12 10 11 12
[4,] 17 14 15 16
[,1] [,2] [,3] [,4]
[1,] 2 9 3 4
[2,] 7 12 7 8
[3,] 12 10 11 12
[4,] 17 14 15 16
[,1] [,2] [,3] [,4]
[1,] 2 9 3 4
[2,] 7 12 7 8
[3,] 12 17 11 12
[4,] 17 14 15 16
[,1] [,2] [,3] [,4]
[1,] 2 9 3 4
[2,] 7 12 7 8
[3,] 12 17 11 12
[4,] 17 22 15 16
[,1] [,2] [,3] [,4]
[1,] 2 9 15 4
[2,] 7 12 7 8
[3,] 12 17 11 12
[4,] 17 22 15 16
[,1] [,2] [,3] [,4]
[1,] 2 9 15 4
[2,] 7 12 24 8
[3,] 12 17 11 12
[4,] 17 22 15 16
[,1] [,2] [,3] [,4]
[1,] 2 9 15 4
[2,] 7 12 24 8
[3,] 12 17 22 12
[4,] 17 22 15 16
[,1] [,2] [,3] [,4]
[1,] 2 9 15 4
[2,] 7 12 24 8
[3,] 12 17 22 12
[4,] 17 22 27 16
[,1] [,2] [,3] [,4]
[1,] 2 9 15 21
[2,] 7 12 24 8
[3,] 12 17 22 12
[4,] 17 22 27 16
[,1] [,2] [,3] [,4]
[1,] 2 9 15 21
[2,] 7 12 24 30
[3,] 12 17 22 12
[4,] 17 22 27 16
[,1] [,2] [,3] [,4]
[1,] 2 9 15 21
[2,] 7 12 24 30
[3,] 12 17 22 39
[4,] 17 22 27 16
[,1] [,2] [,3] [,4]
[1,] 2 9 15 21
[2,] 7 12 24 30
[3,] 12 17 22 39
[4,] 17 22 27 32

array_reshape() not reshaping arrays as desired

I have "old_array", I want to reshape it to become "new_array" using array_reshape()
old_array <- array(seq(1,30,1),c(2,3,5))
new_array <- t(array(seq(1,30,1),c(6,5)))
The old_array is:
, , 1
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
, , 2
[,1] [,2] [,3]
[1,] 7 9 11
[2,] 8 10 12
, , 3
[,1] [,2] [,3]
[1,] 13 15 17
[2,] 14 16 18
, , 4
[,1] [,2] [,3]
[1,] 19 21 23
[2,] 20 22 24
, , 5
[,1] [,2] [,3]
[1,] 25 27 29
[2,] 26 28 30
The new_array is:
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 2 3 4 5 6
[2,] 7 8 9 10 11 12
[3,] 13 14 15 16 17 18
[4,] 19 20 21 22 23 24
[5,] 25 26 27 28 29 30
I tried the following code, however the reshaped array is not the way I want:
array_reshape(old_array,c(6,5))
Expected results:
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 2 3 4 5 6
[2,] 7 8 9 10 11 12
[3,] 13 14 15 16 17 18
[4,] 19 20 21 22 23 24
[5,] 25 26 27 28 29 30
Actual results:
[,1] [,2] [,3] [,4] [,5]
[1,] 1 7 13 19 25
[2,] 3 9 15 21 27
[3,] 5 11 17 23 29
[4,] 2 8 14 20 26
[5,] 4 10 16 22 28
[6,] 6 12 18 24 30
You can call matrix and specify the dimensions you desire. Given how R fills matrices, you need to specify byrow = TRUE in this scenario:
old_array <- array(seq(1,30,1),c(2,3,5))
matrix(old_array, nrow = dim(old_array)[3], ncol = prod(dim(old_array)[1:2]), byrow = TRUE)
#> [,1] [,2] [,3] [,4] [,5] [,6]
#> [1,] 1 2 3 4 5 6
#> [2,] 7 8 9 10 11 12
#> [3,] 13 14 15 16 17 18
#> [4,] 19 20 21 22 23 24
#> [5,] 25 26 27 28 29 30
Created on 2019-03-31 by the reprex package (v0.2.1)
First, you want a 5x6 matrix. Your current code is asking for a return of 6x5 so you would want to write
array_reshape(old_array, c(5,6))
However, your old_array is returning 5 different matrices all 2x3. Since you are filling it in by row, it looks like array_reshape will take the first value from each row of each separate matrix and then since you are telling it to have 6 columns it then grabs the second value of the first matrix to fill out the first row of the 5x6. It then repeats this pattern to fill in the other 4 rows. This will return:
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 7 13 19 25 3
[2,] 9 15 21 27 5 11
[3,] 17 23 29 2 8 14
[4,] 20 26 4 10 16 22
[5,] 28 6 12 18 24 30
Can you remove c(2,3,5) from your old_array line? It will work fine then. Otherwise array_reshape is not the appropriate function in this case. But, if you really want to use it, you can tell it to fill a 6x5 matrix by column and then transpose the matrix. This will give you the result you want:
t(array_reshape(old_array, c(6,5), "F"))
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 2 3 4 5 6
[2,] 7 8 9 10 11 12
[3,] 13 14 15 16 17 18
[4,] 19 20 21 22 23 24
[5,] 25 26 27 28 29 30

How do I understand this index matrix in R

Here I have a
x <- array(1:20, dim=c(4,5))
x
[,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
I also have a index array
i <- array(c(1:3,3:1), dim=c(3,2))
[,1] [,2]
[1,] 1 3
[2,] 2 2
[3,] 3 1
Then
x[i]
will extract X[1,3], X[2,2] and X[3,1]
However, what if I have
i <- array(c(1:3,3:1), dim=c(2,3))
The output is
x[i]
[1] 1 2 3 3 2 1
How can I understand this result?

Resources