How to create a matrix of lists in R? - arrays

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)

Related

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 can I create a static array in R

I need to create a static array for my data structure class and I chose to code in R instead of java.
How can I create a static array? I have tried
> array <- array(1:10, dim=c(1,10))
> array
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 1 2 3 4 5 6 7 8 9 10
but I can still add a 11th value to the array
> array[11] <- 11
> array
[1] 1 2 3 4 5 6 7 8 9 10 11
How can I prevent this from happening?
I am also not aware of a mechanism to achieve this. But the following might give you an idea how something like a static array might be achieved.
I assing a class static_vector to a vector as follows:
x <- 1:10
class(x) <- "static_vector"
Next I define a new method for the assingment operator [<- for this class:
"[<-.static_vector" <- function(x, i, value) {
if (any(i > length(x))) {
warning("Size of vector can not be changed!")
} else {
class(x) <- NULL
x[i] <- value
class(x) <- "static_vector"
}
return (x)
}
Edit: Following nicola's remark, I added any() in the first line of the function body.
Now, the following will still work and do what is expected
x[5] <- 0
but this will issue a warning and leave x unchanged:
x[11] <- 11
There are probably other methods to define before you can be sure that there is no way to change the size of x.
You can give your array a class attribute then define a [ method for it. A simple version could be something like,
`[.thing` <- function(x, i) {
if (i > length(x)) stop("index outside range")
else x[[i]]
}
arr <- array(1:10, dim=c(1,10))
class(arr) <- c("thing", class(arr))
arr[1]
# [1] 1
arr[11]
# Error in `[.thing`(arr, 11) (from ...) : index outside range

Divide every slice of a matrix in an array by its own vector?

Suppose I have two arrays (or tensors if tensor package is needed)
dim(Xbeta)
products draws Households
13 20 10
dim(denom)
1 20 10
set.seed(1)
Xbeta=array(rnorm(13*20*10,0,1),dim=c(13,20,10))
denom=array(rnorm(1*20*10,0,1),dim=c(1,20,10))
Without looping, I want to do the following:
for(i in 1:10){
Xbeta[,,i]=t(t(Xbeta[,,i]) / denom[,,i])
}
I want to to divide each column in Xbeta[,,i] slice by each corresponding number in denom[,,i].
For example...Xbeta[,1,i]/denom[,1,i]...etc
You can avoid looping and replication by (1) 3-dimensionally transposing the numerator array and (2) flattening the denominator array to a vector, such that the division operation will naturally cycle the incomplete denominator vector across the entirety of the transposed numerator array in such a way that the data lines up the way you want. You then must 3-dimensionally "untranspose" the result to get back the original transposition.
aperm(aperm(Xbeta,c(2,3,1))/c(denom),c(3,1,2));
The first call to aperm() transposes columns to rows, z-slices to columns, and rows to z-slices. The c() call on denom flattens the denominator array to a vector, because when cycling, we don't care about dimensionality. The final call to aperm() reverses the original transposition.
To go into more detail about the logic of this solution, what you have with your inputs is basically a vector of divisors per z-slice of the numerator array, and you want to apply each divisor to every row of the corresponding z-slice and column. This means the vector of divisors must be applied across columns, first-and-foremost, and then, as each denominator z-slice is exhausted, applied across numerator z-slices. After a complete row (covering all z-slices in the row) of the numerator array has been exhausted, the entirety of the denominator vector has been exhausted, causing it to be cycled back to the beginning for the next row of the numerator array.
See https://stat.ethz.ch/R-manual/R-devel/library/base/html/aperm.html.
For a rough idea on performance:
r> set.seed(1);
r> Xbeta <- array(rnorm(13*20*10,0,1), dim=c(13,20,10) );
r> denom <- array(rnorm(1*20*10,0,1), dim=c(1,20,10) );
r> robert <- function() { result <- array(NA, dim=c(13,20,10) ); for (i in 1:10) { result[,,i] <- t(t(Xbeta[,,i]) / denom[,,i]); }; };
r> andre <- function() { denom_myVersion <- array(rep(c(denom), each=13 ), c(13,20,10) ); result <- Xbeta / denom_myVersion; };
r> bgoldst <- function() { result <- aperm(aperm(Xbeta,c(2,3,1))/c(denom),c(3,1,2)); };
r> N <- 99999;
r> system.time({ replicate(N, robert() ); });
user system elapsed
25.421 0.000 25.440
r> system.time({ replicate(N, andre() ); });
user system elapsed
12.578 0.594 13.283
r> system.time({ replicate(N, bgoldst() ); });
user system elapsed
8.484 0.594 9.142
Also, as a general recommendation, it is helpful (for both questioners and answerers) to present these kinds of problems using minimal sample input, e.g.:
r> n <- array(1:12,dim=c(2,3,2)); n;
, , 1
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
, , 2
[,1] [,2] [,3]
[1,] 7 9 11
[2,] 8 10 12
r> d <- array(1:6,dim=c(1,3,2)); d;
, , 1
[,1] [,2] [,3]
[1,] 1 2 3
, , 2
[,1] [,2] [,3]
[1,] 4 5 6
r> aperm(aperm(n,c(2,3,1))/c(d),c(3,1,2));
, , 1
[,1] [,2] [,3]
[1,] 1 1.5 1.666667
[2,] 2 2.0 2.000000
, , 2
[,1] [,2] [,3]
[1,] 1.75 1.8 1.833333
[2,] 2.00 2.0 2.000000
# Is this what you're looking for?
Xbeta <- array(rnorm(13*20*10,0,1),dim=c(13,20,10))
denom <- array(rnorm(1*20*10,0,1),dim=c(1,20,10))
div.list <- sapply(1:10, FUN = function(x) t(Xbeta[,,x]) / denom[,,x], simplify = FALSE)
result <- array(do.call(c, div.list), dim = dim(Xbeta)[c(2,1,3)])
I'm not sure why you choose a 3-dimensional array for the denon. Anyway, this can be done by paying close attention to how these numbers are stored in memory. In an array the first dimensions "moves the fastest". By replicating the denom values 13 times "each" then you create an array with the exact same dimensions as your numerator.
So, let's test it out:
Let's save the ramdom values so we can use them for both methods:
set.seed(1)
Num_2600 <- rnorm(13*20*10,0,1)
Denom_200 <- rnorm(20*10,0,1)
Xbeta=array(Num_2600,dim=c(13,20,10))
denom=array(Denom_200,dim=c(1,20,10))
Your_result <- array(NA, dim=c(13,20,10))
Your code gives:
for(i in 1:10){
Your_result[,,i] <- t(t(Xbeta[,,i]) / denom[,,i])
}
My code:
denom_myVersion <- array(rep( Denom_200 , each=13), c(13,20,10))
> all(Your_result == Xbeta / denom_myVersion)
[1] TRUE
>
So we get the same results. The hard part is how to decide how to replicate so the numbers fall in the right spot. Notice:
denom_myVersion <- array(rep( Denom_200 , times=13), c(13,20,10))
> all(Your_result == Xbeta / denom_myVersion)
[1] FALSE
>
With 'each' as a parameter in rep each element is repeated 13 times before going to the next element. With times, the whole vector is repeated 13 times. Compare:
> rep(1:3, each =3)
[1] 1 1 1 2 2 2 3 3 3
> rep(1:3, times=3)
[1] 1 2 3 1 2 3 1 2 3

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

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 :)

Resources