Reducing a 3d array to 2d - r

Is there a more succinct, one-liner way to do the following?
x <- array(1:12, dim = c(3, 2, 2))
> x[1,,]
[,1] [,2]
[1,] 1 7
[2,] 4 10
> x[2,,]
[,1] [,2]
[1,] 2 8
[2,] 5 11
> x[3,,]
[,1] [,2]
[1,] 3 9
[2,] 6 12
# Reduce 3d array to 2d (Is there a more elegant way?)
y <- x
dim(y) <- c(nrow(y), 4)
> y
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12

You can just feed your original array to the array constructor again, and use dim to get the dimension you want to preserve:
y <- array(x, dim = c(dim(x)[1], 4))
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
If you wanted a version that doesn't rely on hardcoding the number of columns:
y <- array(x, dim = c(dim(x)[1], dim(x)[2] * dim(x)[3]))

Related

R accessing a matrix to an array 3d

I would like to access an array 3d with a matrix. Here an example of the desired output:
a <- array(1:18, dim=c(3,3,2))
a
, , 1
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
, , 2
[,1] [,2] [,3]
[1,] 10 13 16
[2,] 11 14 17
[3,] 12 15 18
b <- array(1:2, dim=c(3,3))
b
[,1] [,2] [,3]
[1,] 1 2 1
[2,] 2 1 2
[3,] 1 2 1
a[b]
[,1] [,2] [,3]
[1,] 1 13 7
[2,] 11 5 17
[3,] 3 15 9
(Should i pass a data frame with 3 columns (indexs + values) instead of a matrix?)
if i do a[b], this is the result:
a[b]
4 11 4
and why?
c <- array(1:2, dim=c(2,2))
a[c]
[1] 1 2 1 2
for b <- array(1:2, dim=c(3,3))
> b
[,1] [,2] [,3]
[1,] 1 2 1
[2,] 2 1 2
[3,] 1 2 1
the indices are read by rows. Thus, as #jogo mentioned, a[b] is actually c(a[1, 2, 1], a[2, 1, 2], a[1, 2, 1])
for C <- array(1:2, dim=c(2,2))
> C
[,1] [,2]
[1,] 1 1
[2,] 2 2
since the dimension of C does not match a (only two out of three fit), in this case a[C] is interpreted as a[c(C)] (thanks to comments from #jogo).

Transform 87x2 matrix into 29x6 in R

Suppose if I have a matrix with dimension 87x2. How can I convert into the dimension 29x6 in r
set.seed(1)
mat1 = matrix(runif(174), 87, 2)
I wanted to have like this below
> matrix(c(1:12), 6, 2)
[,1] [,2]
[1,] 1 7
[2,] 2 8
[3,] 3 9
[4,] 4 10
[5,] 5 11
[6,] 6 12
> matrix(c(1:12), 2, 6)
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 3 5 7 9 11
[2,] 2 4 6 8 10 12
Thank you in advance.
You can do the following:
mat1 <- matrix(c(1:12), 6, 2)
matrix(mat1, nrow = 2, ncol = 6)
# [,1] [,2] [,3] [,4] [,5] [,6]
#[1,] 1 3 5 7 9 11
#[2,] 2 4 6 8 10 12
Or set the dimensions directly using dim
dim(mat1) <- c(2, 6)

Sample from a matrix and split sampled and non sampled values in R

I want to sample 'n' rows from a matrix:
data <- matrix(data = 1:12, nrow = 4, ncol = 3)
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
I use the following code :
selection <-sample(nrow(data),size = 2, replace = FALSE)
data[selection,]
[,1] [,2] [,3]
[1,] 4 8 12
[2,] 3 7 11
Is there a way I could return a matrix containing only the rows that haven't been sampled? In this case:
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
Many thanks in advance.

Minimum of cells in two matrices within a moving kernel

I have two matrices m1 and m2.
m1 <- matrix(1:16, ncol = 4)
m2 <- matrix(16:1, ncol = 4)
# > m1
# [,1] [,2] [,3] [,4]
# [1,] 1 5 9 13
# [2,] 2 6 10 14
# [3,] 3 7 11 15
# [4,] 4 8 12 16
# > m2
# [,1] [,2] [,3] [,4]
# [1,] 16 12 8 4
# [2,] 15 11 7 3
# [3,] 14 10 6 2
# [4,] 13 9 5 1
I want to find the minimum between the two matrices for each cell within a moving kernel of 3x3. The outer margines should be ignored, i.e. they can be filled with NAs and the min function should then have na.rm = TRUE. The result should look like this:
# > m3
# [,1] [,2] [,3] [,4]
# [1,] 1 1 3 3
# [2,] 1 1 2 2
# [3,] 2 2 1 1
# [4,] 3 3 1 1
I have already tried a combination of pmin{base} and runmin{caTools} like this:
pmin(runmin(m1, 3, endrule = "keep"),
runmin(m2, 3, endrule = "keep"))
However, this did not work. Probably due to the fact that
"If x is a matrix than each column will be processed separately."
(from ?runmin)
Is there any package, that performs such operations, or is it possible to apply?
Here is a base R approach:
m = pmin(m1, m2)
grid = expand.grid(seq(nrow(m)), seq(ncol(m)))
x = apply(grid, 1, function(u) {
min(m[max(1,u[1]-1):min(nrow(m), u[1]+1), max(1,u[2]-1):min(ncol(m), u[2]+1)])
})
dim(x) = dim(m)
#> x
# [,1] [,2] [,3] [,4]
#[1,] 1 1 3 3
#[2,] 1 1 2 2
#[3,] 2 2 1 1
#[4,] 3 3 1 1

Rotate a Matrix in R by 90 degrees clockwise

I have a matrix in R like this:
|1|2|3|
|1|2|3|
|1|2|3|
Is there an easy way to rotate the entire matrix by 90 degrees clockwise to get these results?
|1|1|1|
|2|2|2|
|3|3|3|
and again rotating 90 degrees:
|3|2|1|
|3|2|1|
|3|2|1|
?
t does not rotate the entries, it flips along the diagonal:
x <- matrix(1:9, 3)
x
## [,1] [,2] [,3]
## [1,] 1 4 7
## [2,] 2 5 8
## [3,] 3 6 9
t(x)
## [,1] [,2] [,3]
## [1,] 1 2 3
## [2,] 4 5 6
## [3,] 7 8 9
90 degree clockwise rotation of R matrix:
You need to also reverse the columns prior to the transpose:
rotate <- function(x) t(apply(x, 2, rev))
rotate(x)
## [,1] [,2] [,3]
## [1,] 3 2 1
## [2,] 6 5 4
## [3,] 9 8 7
rotate(rotate(x))
## [,1] [,2] [,3]
## [1,] 9 6 3
## [2,] 8 5 2
## [3,] 7 4 1
rotate(rotate(rotate(x)))
## [,1] [,2] [,3]
## [1,] 7 8 9
## [2,] 4 5 6
## [3,] 1 2 3
rotate(rotate(rotate(rotate(x))))
## [,1] [,2] [,3]
## [1,] 1 4 7
## [2,] 2 5 8
## [3,] 3 6 9
90 degree counter clockwise rotation of R matrix:
Doing the transpose prior to the reverse is the same as rotate counter clockwise:
foo = matrix(1:9, 3)
foo
## [,1] [,2] [,3]
## [1,] 1 4 7
## [2,] 2 5 8
## [3,] 3 6 9
foo <- apply(t(foo),2,rev)
foo
## [,1] [,2] [,3]
## [1,] 7 8 9
## [2,] 4 5 6
## [3,] 1 2 3
m <- matrix(rep(1:3,each=3),3)
[,1] [,2] [,3]
[1,] 1 2 3
[2,] 1 2 3
[3,] 1 2 3
t(m[nrow(m):1,])
[,1] [,2] [,3]
[1,] 1 1 1
[2,] 2 2 2
[3,] 3 3 3
m[nrow(m):1,ncol(m):1]
[,1] [,2] [,3]
[1,] 3 2 1
[2,] 3 2 1
[3,] 3 2 1
t(m)[ncol(m):1,]
[,1] [,2] [,3]
[1,] 3 3 3
[2,] 2 2 2
[3,] 1 1 1
An easy way to rotate a matrix by 180° is this:
m <- matrix(1:8,ncol=4)
# [,1] [,2] [,3] [,4]
# [1,] 1 3 5 7
# [2,] 2 4 6 8
rot <- function(x) "[<-"(x, , rev(x))
rot(m)
# [,1] [,2] [,3] [,4]
# [1,] 8 6 4 2
# [2,] 7 5 3 1
rot(rot(m))
# [,1] [,2] [,3] [,4]
# [1,] 1 3 5 7
# [2,] 2 4 6 8
R methods to rotate a matrix 90 degrees and -90 degrees
#first reverse, then transpose, it's the same as rotate 90 degrees
rotate_clockwise <- function(x) { t( apply(x, 2, rev))}
#first transpose, then reverse, it's the same as rotate -90 degrees:
rotate_counter_clockwise <- function(x) { apply( t(x),2, rev)}
#or if you want a library to help make things easier to read:
#install.packages("pracma")
library(pracma)
rotate_one_eighty <- function(x) { rot90(x, 2) }
rotate_two_seventy <- function(x) { rot90(x, -1) }
foo = matrix(1:9, 3)
foo
foo = rotate_clockwise(foo)
foo
foo = rotate_counter_clockwise(foo)
foo
foo = rotate_one_eighty(foo)
foo
Prints:
[,1] [,2] [,3]
[1,] 1 4 7 #original matrix
[2,] 2 5 8
[3,] 3 6 9
[,1] [,2] [,3]
[1,] 3 2 1
[2,] 6 5 4 #rotated 90 degrees
[3,] 9 8 7
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8 #rotated -90 degrees
[3,] 3 6 9
[,1] [,2] [,3]
[1,] 9 6 3
[2,] 8 5 2 #rotated 180 degrees
[3,] 7 4 1
Notice that rotating a matrix clockwise, then counterclockwise returns the numbers to their original position, then rotating by 180 is like rotating by 90 twice.
Or combined in a single function (based on Eric Leschinski):
rotate <- function(x, clockwise=T) {
if (clockwise) { t( apply(x, 2, rev))
} else {apply( t(x),2, rev)}
}

Resources