Combining vectors in a subset of list of lists - r

I'd like to get a matrix mat out by combining vectors in a subset of list of lists. Following the way to do the same using a for loop. I am wondering if there is a faster way to do it.
i <- 1 # the subset
mat<- matrix(NA, ncol = p, nrow = n)
for (j in 1 : p) {
mat[, j] <- list_of_list[[j]][[i]]$the_vector
}
EDIT:
I am after the vectors indexed/subseted by 'i' at any given time. Also, the list_of_list has objects other than the_vector as well.
EDIT 2:
Adding a working example below.
lst <- list()
list_of_list <- list()
lst[[1]] <- list(a="a", c="b1", the_vector = 1:5)
lst[[2]] <- list(a="b", c="b2", the_vector = 1:5+1)
lst[[3]] <- list(a="c", c="b3", the_vector = 1:5+2)
list_of_list[[1]] <- lst
lst[[1]] <- list(a="a", c="b1", the_vector = 1:5*0)
lst[[2]] <- list(a="b", c="b2", the_vector = 1:5*1)
lst[[3]] <- list(a="c", c="b3", the_vector = 1:5*22)
list_of_list[[2]] <- lst
i <- 1 # the subset
p <- 2 # length of the list of list
n <- 5 # length of the vector
mat<- matrix(NA, ncol = p, nrow = n)
for (j in 1 : p) {
mat[, j] <- list_of_list[[j]][[i]]$the_vector
}

You may try the sapply() function:
i <- 1L
mat <- sapply(list_of_list, function(.x) .x[[i]]$the_vector)
mat
[,1] [,2]
[1,] 1 0
[2,] 2 0
[3,] 3 0
[4,] 4 0
[5,] 5 0
I have not benchmarked the code to make sure this is faster in terms of execution speed but it definitely requires fewer key strokes.
sapply() applies a function over a list or vector and is a kind of implied for loop.

You can just unlist your list then reshape it as a matrix:
matrix(unlist(list(list(1,2,3,4),list(5,6,7,8),list(9,10,11,12))), nrow=3, byrow = T)
[,1] [,2] [,3] [,4]
[1,] 1 2 3 4
[2,] 5 6 7 8
[3,] 9 10 11 12

I am not sure if you are looking for something like this. It will give you a list of 3 matrices corresponding to vector from list_of_list's child lists.
mapply(list_of_list[[1]],list_of_list[[2]],
FUN = function(x,y){t(mapply(x$the_vector,y$the_vector,
FUN = function(u,v){matrix(c(u,v),ncol=2,byrow = F,dimnames = NULL)},
SIMPLIFY = T))},SIMPLIFY = F)
#[[1]]
# [,1] [,2]
#[1,] 1 0
#[2,] 2 0
#[3,] 3 0
#[4,] 4 0
#[5,] 5 0
#[[2]]
# [,1] [,2]
#[1,] 2 1
#[2,] 3 2
#[3,] 4 3
#[4,] 5 4
#[5,] 6 5
#[[3]]
# [,1] [,2]
#[1,] 3 22
#[2,] 4 44
#[3,] 5 66
#[4,] 6 88
#[5,] 7 110

Here is another solution really similar to #TUSHAr but that might maybe more modular:
## Lapply wrapping function that outputs a matrix
lapply.wrapper <- function(i, list_of_list) {
matrix(unlist(lapply(list_of_list, function(X, i) X[[i]]$the_vector, i = i)), ncol = length(list_of_list))
}
## Using the wrapper on the first subset:
lapply.wrapper(1, list_of_list)
# [,1] [,2]
#[1,] 1 0
#[2,] 2 0
#[3,] 3 0
#[4,] 4 0
#[5,] 5 0
## Applying the function to all subsets
sapply(1:length(list_of_list[[1]]), lapply.wrapper, list_of_list, simplify = FALSE)
#[[1]]
# [,1] [,2]
#[1,] 1 0
#[2,] 2 0
#[3,] 3 0
#[4,] 4 0
#[5,] 5 0
#
#[[2]]
# [,1] [,2]
#[1,] 2 1
#[2,] 3 2
#[3,] 4 3
#[4,] 5 4
#[5,] 6 5
#
#[[3]]
# [,1] [,2]
#[1,] 3 22
#[2,] 4 44
#[3,] 5 66
#[4,] 6 88
#[5,] 7 110

Related

How to create a new matrix by subtracting columns in a given matrix?

mat_sub <- function(x){
nc <- ncol(x)
for (i in 1:nc){
s <- x[,i]-x[,i-1]
}
Z <- cbind(x,s)
Z}
Please help in understanding where I am doing wrong.
As stated in comments you need to start the for loop at the second column, else i - 1 gets zero and that can't be subsetted. The other issue is s which gets overwritten in each iteration. You want to define a two-dimensional array (i.e. a matrix) beforehand, with dimensions of your original matrix minus one column, that gets filled in each iteration.
You may want to correct your code to:
mat_sub <- function(x) {
nc <- ncol(x)
s <- array(NA, dim(x))[, -nc]
for (i in 2:nc) {
s[, i - 1] <- x[, i] - x[, i - 1]
}
Z <- cbind(x, s)
Z
}
m <- matrix(1:12, 3, 4)
mat_sub(m)
# [,1] [,2] [,3] [,4] [,5] [,6] [,7]
# [1,] 1 4 7 10 3 3 3
# [2,] 2 5 8 11 3 3 3
# [3,] 3 6 9 12 3 3 3
Alternatively, in R you may simply do vectorized calculations including subtracting matrices.
cbind(m, m[, -1] - m[, -ncol(m)])
# [,1] [,2] [,3] [,4] [,5] [,6] [,7]
# [1,] 1 4 7 10 3 3 3
# [2,] 2 5 8 11 3 3 3
# [3,] 3 6 9 12 3 3 3
You are over-writing s every time in the loop. Also you start the loop with 1 in which case there is no i-1 i.e 0th column.
You can try :
mat_sub <- function(x){
nc <- ncol(x)
x[, 2:nc] - x[, 1:(nc-1)]
}
Using an example :
set.seed(123)
mat <- matrix(sample(16), 4)
mat
# [,1] [,2] [,3] [,4]
#[1,] 15 10 4 11
#[2,] 16 2 12 13
#[3,] 3 6 7 8
#[4,] 14 5 1 9
mat_sub(mat)
# [,1] [,2] [,3]
#[1,] -5 -6 7
#[2,] -14 10 1
#[3,] 3 1 1
#[4,] -9 -4 8

Class of output object differs as input data differs

I am trying to draw a variable number of samples for each of n attempts. In this example n = 8 because length(n.obs) == 8. Once all of the samples have been drawn I want to combine them into a matrix.
Here is my first attempt:
set.seed(1234)
n.obs <- c(2,1,2,2,2,2,2,2)
my.samples <- sapply(1:8, function(x) sample(1:4, size=n.obs[x], prob=c(0.1,0.2,0.3,0.4), replace=TRUE))
my.samples
This approach produces a list.
class(my.samples)
#[1] "list"
I identify the number of columns needed in the output matrix using:
max.len <- max(sapply(my.samples, length))
max.len
#[1] 2
The output matrix can be created using:
corrected.list <- lapply(my.samples, function(x) {c(x, rep(NA, max.len - length(x)))})
output.matrix <- do.call(rbind, corrected.list)
output.matrix[is.na(output.matrix)] <- 0
output.matrix
# [,1] [,2]
#[1,] 4 3
#[2,] 3 0
#[3,] 3 2
#[4,] 3 4
#[5,] 4 3
#[6,] 3 3
#[7,] 3 4
#[8,] 1 4
The above approach seems to work fine as along as n.obs includes multiple values and at least one element in n.obs > 1. However, I want the code to be flexible enough to handle each of the following n.obs:
The above sapply statement returns a 2 x 8 matrix with the following n.obs.
set.seed(1234)
n.obs <- c(2,2,2,2,2,2,2,2)
The above sapply statement returns an integer with the following n.obs.
set.seed(3333)
n.obs <- c(1,1,1,1,1,1,1,1)
The above sapply statement returns a list with the following n.obs.
n.obs <- c(0,0,0,0,0,0,0,0)
Here are example desired results for each of the above three n.obs:
desired.output <- matrix(c(4, 3,
3, 3,
2, 3,
4, 4,
3, 3,
3, 3,
4, 1,
4, 2), ncol = 2, byrow = TRUE)
desired.output <- matrix(c(2,
3,
4,
2,
3,
4,
4,
1), ncol = 1, byrow = TRUE)
desired.output <- matrix(c(0,
0,
0,
0,
0,
0,
0,
0), ncol = 1, byrow = TRUE)
How can I generalize the code so that it always returns a matrix with eight rows regardless of the n.obs used as input? One way would be to use a series of if statements to handle problematic cases, but I thought there might be a simpler and more efficient solution.
We can write a function :
get_matrix <- function(n.obs) {
nr <- length(n.obs)
my.samples <- sapply(n.obs, function(x)
sample(1:4, size=x, prob=c(0.1,0.2,0.3,0.4), replace=TRUE))
max.len <- max(lengths(my.samples))
mat <- matrix(c(sapply(my.samples, `[`, 1:max.len)), nrow = nr, byrow = TRUE)
mat[is.na(mat)] <- 0
mat
}
Checking output :
get_matrix(c(2,1,2,2,2,2,2,2))
# [,1] [,2]
#[1,] 1 4
#[2,] 4 0
#[3,] 4 3
#[4,] 4 4
#[5,] 4 2
#[6,] 4 3
#[7,] 4 4
#[8,] 4 4
get_matrix(c(1,1,1,1,1,1,1,1))
# [,1]
#[1,] 4
#[2,] 4
#[3,] 3
#[4,] 4
#[5,] 2
#[6,] 4
#[7,] 1
#[8,] 4
get_matrix(c(0,0,0,0,0,0,0,0))
# [,1]
#[1,] 0
#[2,] 0
#[3,] 0
#[4,] 0
#[5,] 0
#[6,] 0
#[7,] 0
#[8,] 0
You could Vectorize the sample function on the size= argument.
samplev <- Vectorize(sample, "size", SIMPLIFY=F)
Wrap samplev into a function and assign maximal length using length<- in an lapply.
FUN <- function(n.obs, prob.=c(.1,.2,.3,.4)) {
s <- do.call(rbind, lapply(
samplev(1:4, size=n.obs, prob=prob., replace=TRUE),
`length<-`, max(n.obs)))
if (!all(dim(s))) matrix(0, length(n.obs))
else ({s[is.na(s)] <- 0; s})
}
Results:
set.seed(1234)
FUN(c(2,1,2,2,2,2,2,2))
# [,1] [,2]
# [1,] 4 3
# [2,] 3 0
# [3,] 3 2
# [4,] 3 4
# [5,] 4 3
# [6,] 3 3
# [7,] 3 4
# [8,] 1 4
FUN(c(2,2,2,2,2,2,2,2))
# [,1] [,2]
# [1,] 2 4
# [2,] 4 4
# [3,] 4 4
# [4,] 4 4
# [5,] 4 4
# [6,] 2 3
# [7,] 1 2
# [8,] 4 3
FUN(c(1,1,1,1,1,1,1,1))
# [,1]
# [1,] 4
# [2,] 4
# [3,] 3
# [4,] 4
# [5,] 2
# [6,] 4
# [7,] 4
# [8,] 1
FUN(c(0,0,0,0,0,0,0,0))
# [,1]
# [1,] 0
# [2,] 0
# [3,] 0
# [4,] 0
# [5,] 0
# [6,] 0
# [7,] 0
# [8,] 0
FUN(c(3, 4))
# [,1] [,2] [,3] [,4]
# [1,] 2 3 3 0
# [2,] 4 3 4 3

Data reshape (from vector to array) in R

I want you to help me about R code.
I have an object, M(list & array). Like this.
object1 <- array(0, c(2,2,2))
M <- list(object1, object1)
Then, I want to reshape m(vector) into M structure.
m <- c(1:16)
When M is list & matrix object, I can use 'relist' function. However, I can't use it to array object. How can I reshape m into M structure??
We can specify the dims in array and use relist
lapply(relist(m, skeleton = M), array, dim(object1))
#[[1]]
#, , 1
# [,1] [,2]
#[1,] 1 3
#[2,] 2 4
#, , 2
# [,1] [,2]
#[1,] 5 7
#[2,] 6 8
#[[2]]
#, , 1
# [,1] [,2]
#[1,] 9 11
#[2,] 10 12
#, , 2
# [,1] [,2]
#[1,] 13 15
#[2,] 14 16
Or another option is
lapply(setNames(split(m, (seq_along(m)-1) %/% lengths(M)[1]), NULL), array, dim(object1))
#[[1]]
#, , 1
# [,1] [,2]
#[1,] 1 3
#[2,] 2 4
#, , 2
# [,1] [,2]
#[1,] 5 7
#[2,] 6 8
#[[2]]
#, , 1
# [,1] [,2]
#[1,] 9 11
#[2,] 10 12
#, , 2
# [,1] [,2]
#[1,] 13 15
#[2,] 14 16
NOTE: Both the solutions are one-line solutions

How do I create an addition table in R?

This should be easy but I can't think of a more elegant way to create an addition table, such as:
x <- 1:3
cbind(x + x[1], x + x[2], x + x[3])
[,1] [,2] [,3]
[1,] 2 3 4
[2,] 3 4 5
[3,] 4 5 6
I tried various versions of lapply() to no avail.
You can either use outer or sapply or expand.grid (in combination with rowSums)
x = 1:3
outer(x, x, "+")
# [,1] [,2] [,3]
#[1,] 2 3 4
#[2,] 3 4 5
#[3,] 4 5 6
sapply(seq_along(x), function(i) sapply(seq_along(x), function(j) x[i]+x[j]))
# [,1] [,2] [,3]
#[1,] 2 3 4
#[2,] 3 4 5
#[3,] 4 5 6
matrix(rowSums(expand.grid(x, x)), ncol = length(x))
# [,1] [,2] [,3]
#[1,] 2 3 4
#[2,] 3 4 5
#[3,] 4 5 6
You could do this:
m <- diag(length(x))
m[] <- x[col(m)] + x[row(m)]
# [,1] [,2] [,3]
#[1,] 2 3 4
#[2,] 3 4 5
#[3,] 4 5 6
OR
matrix(x,length(x),length(x),byrow = TRUE) + x

R Create Matrix From an Operation on a "Row" Vector and a "Column" Vector

First create a "row" vector and a "column" vector in R:
> row.vector <- seq(from = 1, length = 4, by = 1)
> col.vector <- {t(seq(from = 1, length = 3, by = 2))}
From that I'd like to create a matrix by, e.g., multiplying each value in the row vector with each value in the column vector, thus creating from just those two vectors:
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 6 10
[3,] 3 9 15
[4,] 4 12 20
Can this be done with somehow using apply()? sweep()? ...a for loop?
Thank you for any help!
Simple matrix multiplication will work just fine
row.vector %*% col.vector
# [,1] [,2] [,3]
# [1,] 1 3 5
# [2,] 2 6 10
# [3,] 3 9 15
# [4,] 4 12 20
You'd be better off working with two actual vectors, instead of a vector and a matrix:
outer(row.vector,as.vector(col.vector))
# [,1] [,2] [,3]
#[1,] 1 3 5
#[2,] 2 6 10
#[3,] 3 9 15
#[4,] 4 12 20
Here's a way to get there with apply. Is there a reason why you're not using matrix?
> apply(col.vector, 2, function(x) row.vector * x)
## [,1] [,2] [,3]
## [1,] 1 3 5
## [2,] 2 6 10
## [3,] 3 9 15
## [4,] 4 12 20

Resources