Processing list object - r

I have a list object in R that contains further lists, of three vectors each. What is the quickest way to generate three matrices, the first of which has all of the first vectors as rows, the second has all of the second vectors as rows, and the third has all of the third? For example, given:
metalist <- list(list(c(1,1),c(11,11),c("a","a")),
list(c(2,2),c(22,22),c("b","b")),
list(c(3,3),c(33,33),c("c","c")))
I would like to get to three matrices (or data.frames), the first consisting of:
1 1
2 2
3 3
The second consisting of
11 11
22 22
33 33
And the third consisting of
a a
b b
c c
Given that in reality the metalist has 50,000 list objects, a for loop that extracts the vector elements and progressively assembles the matrices takes forever, so I would be looking for something quicker. I'm guessing there may be some clever use of unlist() but I can't figure it out.

The pattern do.call(Map,c(f=___,...)) is a useful one to have in your toolbox. Using list in the blank "transposes" the structure, using rbind will produce your desired matrices:
do.call(Map,c(f=rbind,metalist))
[[1]]
[,1] [,2]
[1,] 1 1
[2,] 2 2
[3,] 3 3
[[2]]
[,1] [,2]
[1,] 11 11
[2,] 22 22
[3,] 33 33
[[3]]
[,1] [,2]
[1,] "a" "a"
[2,] "b" "b"
[3,] "c" "c"

The following will create a list of three matrices:
my_outcome <- list()
for (i in 1:3)
{
my_outcome[[i]] <- t(as.data.frame(lapply(metalist, `[[`, i)))
}
It does use a loop, but only over the number of matrices, so it should work in your case.

If you would like to completely ignore for loops, the following also gets the job done:
lapply(1:3, function(y) {
do.call(rbind,lapply(metalist, function(x) x[[y]]))
})

Related

Calling an assigned variable created within a function in R, within the same function

I am writing a function to solve a Sudoku puzzle. Part of this function will be used to split the matrix into three 9x3 matrices. I shall then perform actions on each one prior to rejoining the matrices to one big matrix.
For this stage, I would like this part of my function to do three things:
split the matrix into three matrices
name each created matrix
call the new matrices in the same function
However, I am struggling with step 3. I have written a function that will split the matrix into three, name each new matrix and if I put in the line envir = globalenv(), the function does return my matrix split into three, 9x3 matrices, each with its individual identifier name. Great!
However, what I would like to do in the next part of the function is to call the new matrices created by step 1 and 2 of the function. I will not know the name of the matrices prior to running the function as I'd like the code to be usable for many matrices no matter the size.
Is there a way of calling the objects created by the assign function, within the main function, when all I will know is that the objects' names will be "mat_n", with n being an integer.
For clarity, here is a simplified version of my code:
m <- matrix(sample(c(0:9), 81, replace = T), ncol = 9, nrow = 9)
matrix_split <- function(x){
i <- 1:length(x[, 1])
a <- 1:sum(i %% 3 == 0) # Will be used to name the temporary matrices
b <- which(i %% 3 == 0) # Will be used to identify where to split main matrix
for(n in a){ # This is to create a number of smaller matrices depending on the
# number multiples of 3 that are present in the length of the object.
nam <- paste("mat_", n, sep = "") # Each new matrix will be named and numbered
# using the assign function below:
assign(nam, x[, c((b[a[n]] - (sum(i %% 3 == 0) - 1)) : b[a[n]])])
# Not a very elegant way of using the loop to split the matrix into blocks of
# three. b[a[n]] returns either 3, 6 or 9, and (sum(i %% == 3) -1 ) = 2. So this
# will return x[, c(1:3)], x[, c(4:6)] and x[, c(7:9)], when spliting the matrix
# into three.
}
}
matrix_split(m)
I am only asking for the specific solution to calling the objects created by the assign function, to be used within my main function after they have been created. This would be a useful skill and is a gap in my programming knowledge (which is not very extensive at all).
This may not be the best way of splitting a matrix either, and I know there are packages already created that will solve a Sudoku puzzle, but I'd like to write my own and there's no better way of learning than doing things badly at first and then improving on it.
How about using ls and parent.frame?
mat_4 <- matrix(LETTERS[1:16],nrow=4)
test <- function(){
ls(parent.frame())[grep("mat_",ls(parent.frame()))]
}
test()
# [1] "mat_4"
get(test())
# [,1] [,2] [,3] [,4]
# [1,] "A" "E" "I" "M"
# [2,] "B" "F" "J" "N"
# [3,] "C" "G" "K" "O"
# [4,] "D" "H" "L" "P"
Or if you want to include the current environment and every level higher, there is sys.frame().
Edit
To get around having to know the names of objects, maybe storing results in the elements of a list is a better plan.
matrix_split <- function(x){
i <- 1:length(x[, 1])
a <- 1:sum(i %% 3 == 0)
b <- which(i %% 3 == 0)
#initialize list
result <- list()
for(n in a){
# assign submatrix to element in the list
result[[n]] <- x[, c((b[a[n]] - (sum(i %% 3 == 0) - 1)) : b[a[n]])]
}
do.call(cbind,result)
}
matrix_split(m)
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
[1,] 6 4 2 9 1 2 8 0 4
[2,] 8 5 5 8 6 1 3 7 8
[3,] 4 7 1 8 3 6 6 0 6
[4,] 3 0 5 0 6 3 2 3 9
[5,] 0 9 7 7 0 1 5 3 2
[6,] 0 8 8 9 9 8 4 9 8
[7,] 6 0 2 9 9 2 4 8 9
[8,] 6 9 6 4 8 1 2 1 1
[9,] 8 4 6 8 5 0 9 5 9

sum rows in a nested list in R

I have a nested list coming out of a program its length is 100. I need to sum all elements of first row and all elements of 2nd row. Here a a small reproducible example. What I need is sum of 1+3+5+7= 16 and sum of 2+4+6+8= 20 as a vector or matrix.
l1<-as.matrix(c(1,2))
l2<-as.matrix(c(3,4))
l3<-as.matrix(c(5,6))
l4<-as.matrix(c(7,8))
ll1<-list(l1,l2)
ll2<-list(l3,l4)
lll<-list(ll1,ll2)
lll
[[1]]
[[1]][[1]]
[,1]
[1,] 1
[2,] 2
[[1]][[2]]
[,1]
[1,] 3
[2,] 4
[[2]]
[[2]][[1]]
[,1]
[1,] 5
[2,] 6
[[2]][[2]]
[,1]
[1,] 7
[2,] 8
I found the purrr package helpful for the function flatten() because it only removes one level of the hierarchy of the lists:
library(magrittr) #for pipes
library(purrr) #for flatten
lll %>% flatten %>% as.data.frame %>% rowSums
Based on akrun's answer it is similar to do.call(c, lll).
We can do this with base R by removing the nested list to a single list using do.call(c then cbind the elements of the list and get the rowSums
rowSums(do.call(cbind, do.call(c, lll)))
#[1] 16 20
Or otherwise we can unlist, create a matrix with 2 columns, and get the colSums
colSums(matrix(unlist(lll), ncol=2, byrow=TRUE))
#[1] 16 20
Reducein base R:
Reduce("+", lapply(Reduce(c, lll), rowSums))
#[1] 16 20

assigning random or automatized names for e.g. matrices in R [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
generate variable names (something like get())
If I want to create matrices with different names in an automatized way, I run into problems.
For example, I want to create three matrices named a1,a2 and a3.
x<-1:3
a<-"a"
listofnames<-paste(a,x) ## a vector with the names that I want to use for my matrices
My problem is to assign a matrix the different names from the vector I created.
For example, to create a matrix called a1 (the first "name" in my vector), this will of course not work at all:
listofnames[1]<-matrix(ncol=2,nrow=2)
But how would I do it?
I've been looking on the internet but can't find any answer..
Thank you so much for your help
Use assign as in:
x<-1:3
a<-"a"
listofnames <-paste(a,x)
set.seed(001)
for(i in 1:length(listofnames)){
assign(listofnames[i], matrix(sample(9), ncol=3))
}
get(listofnames[1])
[,1] [,2] [,3]
[1,] 3 6 8
[2,] 9 2 7
[3,] 5 4 1
get(listofnames[2])
[,1] [,2] [,3]
[1,] 1 5 6
[2,] 2 7 3
[3,] 8 4 9
get(listofnames[3])
[,1] [,2] [,3]
[1,] 4 2 5
[2,] 7 9 3
[3,] 8 1 6
Once you assign matrices to the names contained in listofnames you can access by using get function as shown above. If you only do listofnames[1] this will give you the firt name in listofnames but not the elements stored under that name, to do so you must use get(listofnames[1])
It might be better if you explain exactly what you are trying to achieve, but you might also want to explore assign():
x <- 1:3
a <- "a"
listofnames <- paste(a, x, sep="")
assign(listofnames[1], matrix(nrow = 2, ncol = 2))
a1
[,1] [,2]
[1,] NA NA
[2,] NA NA

R -- Sorting data in a matrix using ranked data in a separate matrix

I am attempting to order data in a matrix using ranked data from a different matrix using R.
I have two matrices (X) and (rank). Each matrix has the same number of columns and rows. I would like to re-order the data in the columns from matrix (X) using the ranked data from the columns in matrix (rank). Column 1 in (X) should be ordered using the ranked data from column 1 in (rank).
I have searched the internet for a couple of days and have not come up with anything. I would appreciate any assistance.
Example:
Matrix (X)
Col1: A,B,C,D,E
Col2: A,B,C,D,E
Matrix (rank)
Col1: 2,4,5,3,1
Col2: 3,2,4,1,5
Goal Matrix (X.rank)
Col1: B,D,E,C,A
Col2: C,B,D,A,E
Thanks again.
If I understand you question correctly, you may want something like this:
R> X <- matrix(c(1:10, (1:10)^2), 10, 2, byrow=FALSE)
R> rank <- seq(10,1,by=-1) # simple decreasing rank
R> X
[,1] [,2]
[1,] 1 1
[2,] 2 4
[3,] 3 9
[4,] 4 16
[5,] 5 25
[6,] 6 36
[7,] 7 49
[8,] 8 64
[9,] 9 81
[10,] 10 100
R> X[rank,]
[,1] [,2]
[1,] 10 100
[2,] 9 81
[3,] 8 64
[4,] 7 49
[5,] 6 36
[6,] 5 25
[7,] 4 16
[8,] 3 9
[9,] 2 4
[10,] 1 1
R>
I am not sure if you want to reorder each column of the matrix independently. To me, that does not make too much sense as we commonly keep matrices with rows per observation and columns for the variables---so you'd want to keep the rows together.
But you may have a different need, and what I have done here for the whole matrix can be done the same way column by column with individual assignments.
Here is an example that might help you with this problem
# vector
x = rnorm(5)
# ranks
y = sample(5)
# sort vector based on ranks
x[match(sort(y), y)]
You can wrap this around an apply call to work on the entire matrix. Note that this may not be the most efficient solution. So if your matrix is large, let people know, so that the solution might be more focused.
EDIT. Here is an extended example that wraps the call in sapply to achieve the same for a matrix.
x = matrix(rnorm(10), ncol = 2) # original matrix to sort
y = cbind(sample(5), sample(5)) # rank matrix for sort order
sapply(1:NCOL(x), function(i) {
.x = x[,i]; .y = y[,i]
.x[match(sort(.y), .y)]
})

Creating tuples from two vectors

If I have two vectors of the same length A<-c(5,10) and B<-c(7,13) how can I easily turn these two vectors into a single tuple vector i. e. c((5,7),(7,13))?
Others have mentioned lists. I see other possibilities:
cbind(A, B) # makes a column-major 2x2-"vector"
rbind(A, B) # an row major 2x2-"vector" which could also be added to an array with `abind`
It is also possible to preserve their "origins"
AB <- cbind(A=A, B=B)
array(c(AB,AB+10), c(2,2,2) )
, , 1
[,1] [,2]
[1,] 5 7
[2,] 10 13
, , 2
[,1] [,2]
[1,] 15 17
[2,] 20 23
> abind( array(c(AB,AB+10), c(2,2,2) ), AB+20)
, , 1
A B
[1,] 5 7
[2,] 10 13
, , 2
A B
[1,] 15 17
[2,] 20 23
, , 3
A B
[1,] 25 27
[2,] 30 33
Your tuple vector c((5,7),(7,13)) is not valid syntax. However, your phrasing makes me think you are thinking of something like python's zip. How do you want your tuples represented in R? R has a heterogeneous (recursive) type list and a homogenous type vector; there are no scalar types (that is, types that just hold a single value), just vectors of length 1 (somewhat an oversimplification).
If you want your tuples to be rows of a matrix (all the same type, which they are here):
rbind(A,B)
If you want a list of vectors
mapply(c, A, B, SIMPLIFY=FALSE)
If you want a list of lists (which is what you would need if A and B are not the same type)
mapply(list, A, B, SIMPLIFY=FALSE)
Putting this all together:
> A<-c(5,10)
> B<-c(7,13)
>
> cbind(A,B)
A B
[1,] 5 7
[2,] 10 13
> mapply(c, A, B, SIMPLIFY=FALSE)
[[1]]
[1] 5 7
[[2]]
[1] 10 13
> mapply(list, A, B, SIMPLIFY=FALSE)
[[1]]
[[1]][[1]]
[1] 5
[[1]][[2]]
[1] 7
[[2]]
[[2]][[1]]
[1] 10
[[2]][[2]]
[1] 13
I'm not certain this is exactly what you're looking for, but:
list(A, B)
which gives you a structure like this:
> str(list(A, B))
List of 2
$ : num [1:2] 5 10
$ : num [1:2] 7 13
and is literally represented like this:
dput(list(A, B))
list(c(5, 10), c(7, 13))
... which is about as close to the suggested end result as you can get, I think.
A list in R is essentially a vector of whatever you want it to be.
If that isn't what you're looking for, it might be helpful if you could expand on what exactly you'd like to do with this vector.
I see what you want to accomplish (because I had the same problem)!
Why not use complex numbers because they are basically nothing else but two dimensional numbers and they are an official data type in R with all the necessary methods available:
A <- complex(real=5,imaginary=10)
B <- complex(real=7,imaginary=13)
c(A,B)
## [1] 5+10i 7+13i
matrix(c(A,B),ncol=1)
## [,1]
## [1,] 5+10i
## [2,] 7+13i

Resources