R: create an array of matrices from a list - arrays

I am trying to create an array from matrices. The matrices are all of identical dimensions (NxN). I have every matrix in a single csv file without header. Data are tab delimited.
In other threads it was suggested to do it as follows:
temp = list.files(pattern="*.csv")
named.list <- lapply(temp, read.csv,header=FALSE, sep = "")
arr <- abind(named.list)
However, this does not create what I want. This creates a 2-dimenaional Nx(N*k) data frame (where N = columns/rows and k = number of matrices).
So in my case I have 5 matrices, 40 columns and 40 rows each. Using abind creates a [1:40, 1:200] data frame.
> str(arr)
int [1:40, 1:200] 0 1 0 0 0 0 0 0 0 0 ...
- attr(*, "dimnames")=List of 2
..$ : NULL
..$ : chr [1:200] "V1" "V2" "V3" "V4" ...
What I want is a [1:40, 1:40, 1:5] three-dimensional array of matrices:
> str(z)
int [1:40, 1:40, 1:5] 0 1 0 0 0 0 0 0 0 0 ...
I think my fundamental problem is that I cannot manage to convert the list of data frames in named.list to a list of matrices.

this worked for me
temp = list.files(pattern="*.csv")
r <- simplify2array(temp)
However, the resulting array had dimensions [nrow, ncol, n] where the first two elements are matrix dimensions and the last is the number of matrices stored in r. My specific analysis required [n, nrow, ncol] to achieve this change I used the aperm function as follows r <- aperm(r, c(3,1,2)) based on this answer function from base package that is a generalization of the transpose t() function

I solved it, the "abind" got me close. The following line was missing:
arr2<-array(arr,dim= c(40,40,5))
This gives me:
str(arr2)
int [1:40, 1:40, 1:5] 0 1 0 0 0 0 0 0 0 0 ...
abind is the way to go. If rbindlist was used beforehand, the structure of the individual data sets gets messed up.

You can use:
library(data.table)
arr <- rbindlist(named.list ,use.names = T,fill = T);

Related

How can we add a vector to a single column of a matrix?

I want to add a vector to just a single column of a matrix.
For example:
a = zeros(5,5);
b = ones(5,1);
I want to add such b only to the second column of a such that the resultant a is
a= [ 0 1 0 0 0;
0 1 0 0 0;
0 1 0 0 0;
0 1 0 0 0;
0 1 0 0 0;]
How can I do this? I have tried doing a+b but it adds one to all the columns.
a(:,2) = a(:,2)+b does this. Specifically, you index all rows, :, of the second column, 2, of a, and add the vector b to that. Read this post for details on various indexing methods.
rahnema1 mentioned that Python-like syntax of adding to or subtracting from an argument does not require that argument to be repeated. You can thus do:
a:(,2) += b

How can I input successive different values from a single vector across the same position in multiple arrays arranged in a list in R?

I have arranged a large number of arrays into a list and I have a vector which is the same length as the number of arrays with different values. For each array in the list, I would like to input the successive specific values in the vector into the same position in the successive arrays in the list.
For example, if I had 10 arrays of 5x3x10 in a list, and a vector of length 10 with 10 different values, I would like the first value of the vector to go into the first array at position [1,1,1], the second value of the vector to go into the second array at position [1,1,1], the third value of the vector to go into the third array at position [1,1,1], and so on to the tenth value of the vector going into the tenth array at position [1,1,1].
Here is my current code (simplified).
All the variables/arrays are provide as necessary.
Currently I have a function that attempts to do this, but the way its written does not allow for the successive values of the variable to be put into the successive arrays. Rather the function tries to put all the values of the variable into the position [1,1,1] of each array, and as such, returns an error.
#Starting variables
dt = 1
person_id <- c("a", "b", "c", "d", "e")
clinic_id <- c("c1", "c2", "c3")
time_id <- seq(2008.5, 2017.5, by = dt)
first <- c(13,14,10,8,6,8,7,9,10,12)
second <- c(16,8,9,4,5,6,2,3,4,5)
numbers <- data.frame(first,second)
dims <- list(person = person_id,
clinic = clinic_id,
time = time_id)
#Create 10 arrays
for (i in 1:10) {
assign(paste("modarrays", i, sep=""),
array(NA, lengths(dims), dims) )
}
#Creating array list with 10 arrays
modarraysall <- lapply(ls(pattern="modarrays"),get)
arraynames <- sapply(ls(pattern="modarrays"),as.name)
names(modarraysall) <- arraynames
#Initial values in array
initval <- function(x){
x[,,1] <- 0.0
x <- x
}
modarraysallnew <- lapply(modarraysall, initval)
#Values from vector of dataframe into array
#This is where it all goes wrong.
numbersintoarray <- function(x){
x[1,1,1] <- numbers$first
x <- x
}
modarraysallnew <- lapply(modarraysallnew, numbersintoarray)
There is no output from this function implementation because I get an error saying
Error in x[1, 1, 1] <- numbers$first :
number of items to replace is not a multiple of replacement length
I think I know what is wrong. This function wants to put the value of numbers$first into position [1,1,1] of each array across the list. However, numbers$first is a length of 10 values where as position [1,1,1] in each array is only one position. Therefore, I know this function is wrong. But how do I write a function that takes each successive value from numbers$first and puts that into each successive array in the list at position [1,1,1].
Below I have shown what I would like the arrays too look like afterwards.
modarrays1[,,1]
clinic
person c1 c2 c3
a 13 0 0
b 0 0 0
c 0 0 0
d 0 0 0
e 0 0 0
modarrays1[,,2]
clinic
person c1 c2 c3
a 14 0 0
b 0 0 0
c 0 0 0
d 0 0 0
e 0 0 0
modarrays1[,,3]
clinic
person c1 c2 c3
a 10 0 0
b 0 0 0
c 0 0 0
d 0 0 0
e 0 0 0
....
modarrays10[,,1]
clinic
person c1 c2 c3
a 12 0 0
b 0 0 0
c 0 0 0
d 0 0 0
e 0 0 0
I realize I could write this out one array at a time. However, in my actual model code I have 54 arrays in the list so would like to be able to write a function to do this instead.
If you want to perform a function element-wise across two different lists or vectors, your best bet is to use mapply or Map. They need a function that takes as many arguments as lists/vectors you are providing. So in your case, you could try:
numbersintoarray <- function(arr, val) {
arr[1, 1, 1] <- val
return(arr)
}
m <- Map(numbersintoarray, modarraysallnew, numbers$first)
m$modarrays1[ , , 1]
# clinic
# person c1 c2 c3
# a 13 0 0
# b 0 0 0
# c 0 0 0
# d 0 0 0
# e 0 0 0

How to find adjacency matrix given a set of links and edges in matlab

I have vector of all edges for example
A = [1;2;3;4];
I also have the matrix of all the links connecting these edges represented by the edge numbers for example
B = [1 3;3 1;1 2;1 2;2 3;4 3];
I would like to construct the adjacency matrix with this data. The matrix should not consider the ordering of the edges in the links For example the second link has edges 1 2 but the matrix should have entries in both 1,2 and 2,1.
So therefore i need an output like this
C = [0 1 1 0;1 0 1 0;1 1 0 1;0 0 1 0];
I cannot think of any other way other than using a for loop for the size of B and then finding the egdes for each link in B and then adding 1's to a pre-initialized 4x4 matrix at i,j where i,j is the link edges.
Is this an efficient way because my real size is many magnitudes greater than 4? Could someone help with a better way to construct the matrix?
You can use sparse to build the matrix, and then optionally convert to full:
result = full(sparse(B(:,1), B(:,2), 1)); % accumulate values
result = result | result.'; % make symmetric with 0/1 values
Equivalently, you can use accumarray:
result = accumarray(B, 1); % accumulate values
result = result | result.'; % make symmetric with 0/1 values
For A = [1;2;3;4]; B = [1 3;3 1;1 2;1 2;2 3;4 3], either of the above gives
result =
4×4 logical array
0 1 1 0
1 0 1 0
1 1 0 1
0 0 1 0

Array inside array in MATLAB

If n=4 for example, How to create an array like this in MATLAB?
[[0] [0 0] [0 0 0] [0 0 0 0]]
Is there a way to create an array inside a for loop, for example ?
This is what I want to achieve (I know it's wrong code):
for i=1:n
table(i)=zeros(i);
end
You need a cell array to hold your numeric vectors. Cell arrays are used in Matlab when the contents of each cell are of different size or type.
Additional comments:
I'm renaming your variable i to k, to avoid shadowing the imaginary unit.
I'm also renaming your variable table to t, to avoid shadowing the table function.
zeros(k) gives a kxk matrix of zeros. To obtain a row vector of zeros use zeros(1,k).
It's better to preallocate the cell array to improve speed.
Taking the above into account, the code is:
n = 4;
t = cell(1,n); %// preallocate: 1xn cell array of empty cells
for k = 1:n
t{k} = zeros(1,k);
end
This gives:
>> celldisp(t)
t{1} =
0
t{2} =
0 0
t{3} =
0 0 0
t{4} =
0 0 0 0
Equivalently, you could replace the for loop by the more compact arrayfun:
result = arrayfun(#(k) zeros(1,k), 1:n, 'uniformoutput', false);

Creating Indicator Matrix

For a vector V of size n x 1, I would like to create binary indicator matrix M of the size n x Max(V) such that the row entries of M have 1 in the corresponding columns index, 0 otherwise.
For eg: If V is
V = [ 3
2
1
4]
The indicator matrix should be
M= [ 0 0 1 0
0 1 0 0
1 0 0 0
0 0 0 1]
The thing about an indicator matrix like this, is it is better if you make it sparse. You will almost always be doing a matrix multiply with it anyway, so make that multiply an efficient one.
n = 4;
V = [3;2;1;4];
M = sparse(V,1:n,1,n,n);
M =
(3,1) 1
(2,2) 1
(1,3) 1
(4,4) 1
If you insist on M being a full matrix, then making it so is simple after the fact, by use of full.
full(M)
ans =
0 0 1 0
0 1 0 0
1 0 0 0
0 0 0 1
Learn how to use sparse matrices. You will gain greatly from doing so. Admittedly, for a 4x4 matrix, sparse will not gain by much. But the example cases are never your true problem. Suppose that n was really 2000?
n = 2000;
V = randperm(n);
M = sparse(V,1:n,1,n,n);
FM = full(M);
whos FM M
Name Size Bytes Class Attributes
FM 2000x2000 32000000 double
M 2000x2000 48008 double sparse
Sparse matrices do not gain only in terms of memory used. Compare the time required for a single matrix multiply.
A = magic(2000);
tic,B = A*M;toc
Elapsed time is 0.012803 seconds.
tic,B = A*FM;toc
Elapsed time is 0.560671 seconds.
a quick way to do this - if you do not require sparse matrix - is to create an identity matrix, of size at least the max(v), then to create your indicator matrix by extracting indexes from v:
m = max(V);
I = eye(m);
V = I(V, :);
You would like to create the Index matrix to be sparse for memory sake. It is as easy as:
vSize = size(V);
Index = sparse(vSize(1),max(V));
for i = 1:vSize(1)
Index(i, v(i)) = 1;
end
I've used this myself, enjoy :)
You can simply combine the column index in V with a row index to create a linear index, then use that to fill M (initialized to zeroes):
M = zeros(numel(V), max(V));
M((1:numel(V))+(V.'-1).*numel(V)) = 1;
Here's another approach, similar to sparse but with accumarray:
V = [3; 2; 1; 4];
M = accumarray([(1:numel(V)).' V], 1);
M=sparse(V,1:size(V,1),1)';
will produce a sparse matrix that you can use in calculations as a full version.
You could use full(M) to "inflate" M to actually store zeros.

Resources