Setting up a 3D matrix in R and accessing certain elements - arrays

I am trying to set up a 3D matrix in R. I guess this is an easy one. However, I didn't find a solution so far.
Let's say we want to create a 365x6x4 matrix.
Also crucial form me is how I can change one entry in the matrix.
Let's say we want to assign the value 204 to the element [304,5,2].

Try this:
ar <- array(someData, c(365, 6, 4));
ar[304,5,2] <- 204;
where someData might be
someData <- rep(0, 365*6*4);
or even better maybe
someData <- rep(NaN, 365*6*4);

A matrix is a special 2-dimensional case of an array. (Quoting from the help for ?matrix).
So, you need array:
x <- array(rep(1, 365*5*4), dim=c(365, 5, 4))
str(x)
num [1:365, 1:5, 1:4] 1 1 1 1 1 1 1 1 1 1 ...
Set a specific value:
x[305, 5, 2] <- 204
Print one slice:
x[305, , ]
[,1] [,2] [,3] [,4]
[1,] 1 1 1 1
[2,] 1 1 1 1
[3,] 1 1 1 1
[4,] 1 1 1 1
[5,] 1 204 1 1

Try this simple example (have made the example a fairly small one so it's clear what's going on - I explain below how to tweak it for your precise question!)...
m = array(1:60, dim=c(3,4,5))
m[2,1,5]
[1] 50
m[2,1,5] = -50
m[2,1,5]
[1] -50
Type m to see the whole 3d array :)
In your example, you'd set up your initial array as m = array(NA, dim=c(365,6,4)) (this will fill it with NAs to start with - do you have data to fill it up with?) And the assignment is m[304,5,2] = 204, of course :)

Related

R: If I have two matrices, one with nearly the same columns but mixed up. How can I effectively map the two matrices?

Of the two matrices have one has i) the columns in different orders and ii) entire columns (every elements in the column) has the opposite different signs. An example would be
A = 1 2
3 4
b = 1.99 -1.02
3.99 -2.99
How can I re-order b such that it looks like:
b = 1.02 1.99
2.99 3.99
Is there away to do this quickly in R?
You could treat it as an optimization problem -- minimize the absolute difference between the two matrices by reordering the columns in one of the matrices.
Example data
A <- matrix(c(1, 2, 3, 4), nrow = 2)
A
[,1] [,2]
[1,] 1 3
[2,] 2 4
b <- matrix(c(-2.99, 3.99, -1.02, 1.99), nrow = 2)
b
[,1] [,2]
[1,] -2.99 -1.02
[2,] 3.99 1.99
Optimization / search
# Data frame with a row for every possible column arrangement
ordering <- (expand.grid(rep(list(1:ncol(A)), ncol(A))))
ordering
Var1 Var2
1 1 1
2 2 1
3 1 2
4 2 2
# Create a function to compute the difference for a particular arrangement
loss <- function(i) {
ord <- unlist(ordering[i, ])
sum(abs(abs(A) - abs(b[, ord])))
}
# Find the best arrangement
result <- optimize(loss, 1:nrow(ordering))
result$minimum # row index from the data frame
[1] 2.145956
# Extract the row to get the actual solution
solution <- unname(unlist(ordering[result$minimum, ]))
solution
[1] 2 1
Verify
A
[,1] [,2]
[1,] 1 3
[2,] 2 4
b[, solution]
[,1] [,2]
[1,] -1.02 -2.99
[2,] 1.99 3.99
Assuming that your matrices are as small as they are in your examples, you could change the order of the columns the following way:
Your example indicates you want to switch the first column and the second column. We can do that by reordering the column indexes like so:
b <- b[ , c(2, 1)]
c(2, 1) indicates that from now on, column 2 will be displayed as the first column and then column 1 will be displayed as the second column. We specify this in the column portion of the index operator and leave the row portion blank.
If we want to change the sign of an entire column, we can perform operations on specific columns like so:
b[ , 1] <- -1*b[ , 1]
This makes it so that every value in what is now the first column gets multiplied by -1.
If the matrix you're dealing with is much bigger, this is probably an impractical approach.

Is there a dimension function that works for vectors, matrices and arrays in R

As we all know the function dim calculates the dimension of a multidemnsional array or matrix.
n = 2
A = matrix(rnorm(n^2),n,n)
dim(A)
Which yields the answer 2,2 as expected. Now the issue is often you don't know if an object will be a vector or a matrix or an array. dim only works on the latter two types. Of course one could write a function as follows
dimVorM = function(x) ifelse( is.vector(x), return(c(1,length(x))), dim(x) )
But is there a better way?
You could write something like this, which would be analogous to NROW and NCOL.
DIM <- function(x) if(is.null(dim(x))) length(x) else dim(x)
I wouldn't return a length-2 vector if something only has one dimension. And don't use ifelse for control flow.
Technically, dim() works for vectors. The function dim() extracts a "dim" attribute and returns its values. A vector doesn't have that attribute dim, so the function dim() rightfully returns NULL.
> x <- 1:10
> attr(x, "dim") <- c(2,5)
> x
[,1] [,2] [,3] [,4] [,5]
[1,] 1 3 5 7 9
[2,] 2 4 6 8 10
> dim(x)
[1] 2 5
> attributes(x)
$dim
[1] 2 5
> dim(x) <- NULL
> x
[1] 1 2 3 4 5 6 7 8 9 10
> dim(x)
NULL
The dim attribute is a vector with one value for each dimension, indicating the number of elements in that dimension. Both NROW and NCOL are constructed in such a way that they consider a vector to be a column vector with 1 column and n rows, and the solution of Hong Ooi is consistent with this.
Also keep in mind that a table is something entirely different. That is not a vector but a one-dimensional array :
> y <- table(iris$Species)
> y
setosa versicolor virginica
50 50 50
> dim(y)
[1] 3
> class(y)
[1] "table"

array in R number of items to replace is not a multiple of replacement length

I would like to ask, how to set a value in array using looping. say like this
a<-3
b<-4
for( i in 1:5)
{
x[i] <- cbind(a*i, b*i)
}
but i always get error saying : In x[i] <- cbind(a * i, b * i) :
number of items to replace is not a multiple of replacement length. I used "paste" but seems it's not the solution. What is the problem ? If it were solved, can I get the value by using ; for example x[2][,2] to get the value of b * 2 ?
thank you
You can do it this way :
a <- 3
b <- 4
i <- 1:5
x <- cbind(a*i, b*i)
Make use of the matrix functions and the fact that R computes directly on vectors and matrices.
In your case, try this:
outer(1:5, 3:4, FUN = "*")
[,1] [,2]
[1,] 3 4
[2,] 6 8
[3,] 9 12
[4,] 12 16
[5,] 15 20

How to create a matrix of lists in R?

What i want to have is a matrix in which each element is a list itself.
See the following example:
1 2 3
1 1,2,4 1,2 1
2 Null 3,4,5,6 1,3
I saw this post, and tried the following but got an error :
b <- array()
b[j, i, ] <- A[i]
where A is a vector itself.
The error was:
Error in b[j, i, ] <- A[i] : incorrect number of subscripts
How should I define and access each element of the matrix and each element of the contained lists?
Update1 :
b<-matrix(list(),nrow = length(d), ncol =length(c))
Error in b[j, i] <- A[i] : replacement has length zero
I want to specify that each element is a list and then try to fill it with various list with different length from zero to n.
Update2 :
running what #BondedDust commented :
b<-matrix(rep(list(),(c*d)),,nrow = length(d), ncol =length(c))
Erorr in b[[j*nrow(b)+i]] <- A[i] : attempt to select less than one element
A :
A[1]<-c(3) F[[1]]<-numeric(0) E[[1]]<-numeric(0)
A[2]<-c(1) F[2]<-c(1) E[2]<-c(1)
A[3]<-c(1) F[3]<-c(2) E[[3]]<-numeric(0)
A[[4]]<-c(1,3) F[[4]]<-numeric(0) E[[4]]<-numeric(0)
A[5]<-c(4) F[5]<-c(4) E[5]<-c(4)
A :values of row 1 , F:row 2 and E :row 3. ( 5 column )
this data is not in this form and is not stored any where,they are the output of another function (there is function in the place of A[i]).the data just show what dose A look likes reproducibly and therefore shows the position in the matrix and gives back the error in update2.A[4] is the element of column 4 row 2.
This builds that matrix although the print method does not display it in the manner you imagined:
matrix( list(c(1,2,4), c(NULL), c(1,2), c(3,4,5,6), c(1), c(1,3)), 2,3)
#---------
[,1] [,2] [,3]
[1,] Numeric,3 Numeric,2 1
[2,] NULL Numeric,4 Numeric,2
Inspect the first element:
> Mlist <- matrix( list(c(1,2,4), c(NULL), c(1,2), c(3,4,5,6), c(1), c(1,3)), 2,3)
> Mlist[1,1]
[[1]]
[1] 1 2 4
> is.matrix(Mlist)
[1] TRUE
> class( Mlist[1,1] )
[1] "list"
Demonstration of creating "matrix of lists" from a list:
> will.become.a.matrix <- list(c(1,2,4), c(NULL), c(1,2), c(3,4,5,6), c(1), c(1,3))
> is.matrix(will.become.a.matrix)
[1] FALSE
> dim(will.become.a.matrix) <- c(2,3)
> is.matrix(will.become.a.matrix)
[1] TRUE
> dim(will.become.a.matrix)
[1] 2 3
> class(will.become.a.matrix[1,1])
[1] "list"
Further requested demonstration:
A<- list(); F=list() E=list()
A[1]<-c(3) ; F[[1]]<-numeric(0); E[[1]]<-numeric(0)
A[2]<-c(1) ; F[2]<-c(1) ; E[2]<-c(1)
A[3]<-c(1) ; F[3]<-c(2) ; E[[3]]<-numeric(0)
A[[4]]<-list(1,3) ;F[[4]]<-numeric(0) ; E[[4]]<-numeric(0)
A[5]<-c(4) ; F[5]<-c(4) ; E[5]<-c(4)
Mlist= c(A,F,E)
M <- matrix(Mlist, length(A), 3)
#=====================================
> M
[,1] [,2] [,3]
[1,] 3 Numeric,0 Numeric,0
[2,] 1 1 1
[3,] 1 2 Numeric,0
[4,] List,2 Numeric,0 Numeric,0
[5,] 4 4 4
You asked (in comments) "....is there a way to define number of column and rows , but not the element itself because they are unknown?"
Answered (initially in comments)
b<-matrix(rep(list(), 6),nrow = 2, ncol =3)
#.... then replace the NULL items with values.
# Need to use "[[": for assignment (which your 'Update 1' did not
# ....and your Update2 only did for some but not all of the assignments.)
b[[1]] <- c(1,2,3,4)

Extract the anti-diagonals from an array

I want to extract the anti-diagonals of an array
m=array(1:18,c(3,3,2))
My best shot
k=dim(m)[3]
mn=matrix(nrow = k, ncol = 3)
for (i in 1:k){
mn=diag(m[,,i][3:1,1:3])
}
This returns 12 14 16, the anti-diagonal of the second matrix in the array. I want to achieve this
[1] 3 5 7
[2] 12 14 16
I want the “anti-diags” as arrays
Manually diag(m[,,1][3:1,1:3]) and diag(m[,,2][3:1,1:3]) works fine, but the array I’m working with is dim(c(3,3,22)), so I thought "loop!"
MQ: How to extract the anti-diagonals from an array using the loop? (better and elegant solutions are more than welcome)
This should work:
mn <- array(NA, dim=dim(m))
for (i in 1:dim(m)[3]){
mn[,,i]=diag(m[,,i][cbind(3:1,1:3)])
}
It was unclear whether you want the "anti-diag" to become the new diag, but that is what your code suggested as the intent. The form matrix[cbind(vec1,vec2)] pulls the (R,C) referenced elements from the matrix.
If you do not want them as arrays then this is an alternate result:
mn <- array(NA, dim=c(2,3))
for (i in 1:dim(m)[3]){
mn[i,]=m[,,i][cbind(3:1,1:3)]
}
mn
[,1] [,2] [,3]
[1,] 3 5 7
[2,] 12 14 16
This is a loopless way of getting the same values:
m[cbind( rep(3:1,2), rep(1:3,2), rep(1:2,each=3)) ]
[1] 3 5 7 12 14 16
You could use lapply across the third dimension and extract the anti-diagonal by first rotating the matrix ( see this great answer ) by reversing the column order and taking the diagonal of that. Basically like this...
out <- lapply( 1:dim(m)[3] , function(x) diag( t( apply( m[,,x] , 2 , rev ) ) ) )
[[1]]
[1] 3 5 7
[[2]]
[1] 12 14 16
If you need them glued together as an array then use do.call...
do.call( rbind , out )
[,1] [,2] [,3]
[1,] 3 5 7
[2,] 12 14 16
In this particular case, a for loop will be much quicker (benchmark it) and you should use #DWin's answer.
It occurs to me that we can simplfy this a bit and avoid using lists and bad use of lapply (by assuming thatm is available outside the scope of lapply) because we can also simply apply across the third dimension of your matrices. So we can apply once to rotate the matrices, then take the diag of each rotated matrix like so...
rotM <- apply( m , 2:3 , rev )
out <- t( apply( rotM , 3 , diag ) )
[,1] [,2] [,3]
[1,] 3 5 7
[2,] 12 14 16

Resources