2d matrix in 3d complex array in r
I have a dataframe data
in R of dim 120,000 rows by 5 columns.
Every 300 lines represents a frame measured at different time intervals (i.e. 400 frames)
Act
I tried to use array(data, c(300, 5, 400))
Expected
Make this framework into a 3d array, dividing data
every 300 lines and join these 400 matrices one after another.
Actual
Reads the values down the first column data
and places them in the first part of the array.
source to share
Another variant:
m1 <- matrix(1:(300*400*5), nrow=300*400, ncol=5)
lst <- lapply(split(seq_len(nrow(m1)),(seq_len(nrow(m1))-1) %/%300 +1),
function(i) m1[i,])
arr1 <- array(0, dim=c(300,5,400))
for(i in 1:400){
arr1[,,i] <- lst[[i]]
}
m1[297:300,]
# [,1] [,2] [,3] [,4] [,5]
#[1,] 297 120297 240297 360297 480297
#[2,] 298 120298 240298 360298 480298
#[3,] 299 120299 240299 360299 480299
#[4,] 300 120300 240300 360300 480300
tail(arr1[,,1],4)
# [,1] [,2] [,3] [,4] [,5]
#[297,] 297 120297 240297 360297 480297
#[298,] 298 120298 240298 360298 480298
#[299,] 299 120299 240299 360299 480299
#[300,] 300 120300 240300 360300 480300
Or as suggested by @Ananda Mahto
library(abind)
arr2 <- abind(lapply(split(seq_len(nrow(m1)),
(seq_len(nrow(m1))-1) %/% 300 + 1), function(x) m1[x, ]), along = 3)
source to share
Here's an approach using dim<-
and aperm
:
Sample data:
set.seed(1)
mat <- matrix(sample(100, 12 * 5, TRUE), ncol = 5)
mat
# [,1] [,2] [,3] [,4] [,5]
# [1,] 27 69 27 80 74
# [2,] 38 39 39 11 70
# [3,] 58 77 2 73 48
# [4,] 91 50 39 42 87
# [5,] 21 72 87 83 44
# [6,] 90 100 35 65 25
# [7,] 95 39 49 79 8
# [8,] 67 78 60 56 10
# [9,] 63 94 50 53 32
# [10,] 7 22 19 79 52
# [11,] 21 66 83 3 67
# [12,] 18 13 67 48 41
Slicing and slicing:
Sliced <- aperm(`dim<-`(t(mat), list(5, 3, 4)), c(2, 1, 3))
Sliced
# , , 1
#
# [,1] [,2] [,3] [,4] [,5]
# [1,] 27 69 27 80 74
# [2,] 38 39 39 11 70
# [3,] 58 77 2 73 48
#
# , , 2
#
# [,1] [,2] [,3] [,4] [,5]
# [1,] 91 50 39 42 87
# [2,] 21 72 87 83 44
# [3,] 90 100 35 65 25
#
# , , 3
#
# [,1] [,2] [,3] [,4] [,5]
# [1,] 95 39 49 79 8
# [2,] 67 78 60 56 10
# [3,] 63 94 50 53 32
#
# , , 4
#
# [,1] [,2] [,3] [,4] [,5]
# [1,] 7 22 19 79 52
# [2,] 21 66 83 3 67
# [3,] 18 13 67 48 41
Adjust the numbers to match your data.
When destroyed, we get:
-
t(mat)
: transfers your matrix (so we now have 5 x 12). -
dim<-(..., list(...))
: will convert this to an array, in this case 5 (string) x 3 (col) x 4 (third dimension). -
aperm
: the result of the last step is a string, so we need to convert it to columns, so this is similar tot
but with multiple dimensions.
They are also very efficient operations. Here's a comparison of this approach to @ akrun's:
m1 <- matrix(1:(300*400*5), nrow=300*400, ncol=5)
am <- function() {
aperm(`dim<-`(t(m1), list(5, 300, 400)), c(2, 1, 3))
}
ak <- function() {
lst <- lapply(split(seq_len(nrow(m1)),(seq_len(nrow(m1))-1) %/%300 +1),
function(i) m1[i,])
arr1 <- array(0, dim=c(300,5,400))
for(i in 1:400){
arr1[,,i] <- lst[[i]]
}
arr1
}
library(microbenchmark)
microbenchmark(am(), ak(), times = 20)
# Unit: milliseconds
# expr min lq median uq max neval
# am() 19.09133 27.63269 31.18292 67.12434 146.2673 20
# ak() 496.11494 518.71223 550.02215 591.27266 699.9834 20
source to share