Assign value to one column of a matrix in a loop - r

I wonder if there is a simple way to produce a list of matrices with sequential names using a "for" loop, and then give one of their columns values.
for(i in 1:3)
{
assign(paste0("matrix",i), matrix(NA, nrow = 4, ncol = 6))
assign(get(paste0("matrix",i))[,1], rep(i, 4))
}
In the above code, I tried to create 3 matrices matrix1, matrix2, and matrix3, whose first columns were aimed to assign the values of rep(1, 4), rep(2, 4), rep(3, 4). However, R gives an error message.
Error in assign(get(paste0("matrix", i))[, 1], rep(i, 4)) :
invalid first argument
Thanks for your help.

If your goal is to make a list of matrices, I would recommend using list. Putting them in a real list and not in the main env as similarly named objects creates a lot more cohesion and makes your code easier to understand.
matrix_list = lapply(1:3, function(x) matrix(NA, nrow = 4, ncol = 6))
names(matrix_list) = paste('matrix', 1:3)
The error you see is probably because assign requires a character as input. Carefully read the docs for assign and get (and never use them again ;) ).

Related

Run function in R that requires two elements and want to compare two by two

I know this might be a pretty simple automatic iterative question.
I am running a PLS regression by using geomorph.
This function requires two 3D arrays inside it (A1 and A2), as can be seen in the documentation in the previous link.
Basically the function would be:
two.b.pls(A1, A2, iter = 999)
The point is that I am having 8 different 3D matrix arrays and want to run the PLS analysis for any possible combination.
More explicitly, if my arrays are named Group_1, Group_2... Group_8, what I need is to iteratively analyse these combinations:
two.b.pls(Group_1, Group_2, iter = 999)
two.b.pls(Group 1, Group 3, iter = 999)
...
two.b.pls(Group_7, Group_8, iter = 999)
If we have object names in a vector, use combn to return the pairwise combinations, get the values and pass them into two.b.pls function
nm1 <- c('Frontal', 'Face', 'Parietal_L', 'Parietal_R', 'Temporal_L', 'Temporal_R', 'Occipital', 'Sphenoid')
out <- combn(nm1, 2, FUN = function(x)
two.b.pls(get(x[1]), get(x[2]), iter = 999), simplify = FALSE)
If we want to get the combination name, an option is to name the list elements with combn output of the vector
names(out) <- combn(nm1, 2, FUN = paste, collapse="_")

Creating list in one line from variables with distinct names and values in R

this is my first question on this forum so I hope I follow all the right procedures.
I was wondering if it's possible to create a list in R from a set of variables with distinct names and values in one line. Specifically, I already have a list list_cond <- list("foo1", "foo2", "foo3",...) and a list of lists list_vals <- list(list(1, 2, 3), list(4, 5, 6), list(7, 8, 9)) and would like to create a list new_list <- list(f("foo1")=2, f("foo2")=5, f("foo3")=8) procedurally where a string modifying function f is applied to each element of list_cond before it is used as a name for the corresponding element which is indexed from list_vals. Is there a way to do this in a single line?
I found sapply as a method in this thread by using USE.NAMES=TRUE but it seems to only generate the names from the function passed in, and the values are just the same as the names. This thread is also related, but I specifically want to generate both the names and the values in the same line, not just add names to the values.
If doing this in one line isn't possible, are there any specific methods that are efficient as opposed to just creating the list and using some apply function to add the names later?
EDIT: as this will be running on a specific server which doesn't have a lot of R packages, so built in functions would be preferable
We extract the second element of the list and then set the names of the list with 'list_cond' (is a list so unlist it to create a vector)
setNames(lapply(list_vals, '[[', 2),
paste0(unlist(list_cond), "_", seq_along(list_vals)))
A tidyverse approach would be
library(tidyverse)
map(list_vals, pluck, 2) %>%
set_names(paste0(unlist(list_cond), "_", seq_along(list_vals)))
data
list_cond <- list("foo1", "foo2", "foo3")
list_vals <- list(list(1, 2, 3), list(4, 5, 6), list(7, 8, 9))

If statement to fill Matrix, incorrect number of subscripts

I am trying to write a for loop where if the cell of one matrix matches a letter it then fills a blank matrix with the entire row that matched. Here is my code
mets<-data.frame(read.csv(file="Metabolite_data.csv",header=TRUE))
full<-length(mets[,6])
A=matrix(,nrow=4930,ncol=8, byrow=T)
for (i in 1:full){
if (mets[i,6]=="A") (A[i,]=(mets[i,]))
}
If I replace the i in the if statement with a single number it works to fill that row of matrix A, however it will not fill more then one row. TIA
You might be getting problems going from data frame to matrix. It could be that just using "mets" as a matrix instead of a data frame could solve your problem, or you could use as.matrix within your for loop. An example of the latter with made-up data since I don't have your "metabolite_data.csv":
mets <- matrix(sample(LETTERS[1:4], 80, replace = TRUE), nrow = 10, ncol = 8)
mets <- as.data.frame(mets)
A <- matrix(nrow = nrow(mets), ncol = ncol(mets), byrow = TRUE)
for(i in 1:nrow(mets)){
if(mets[i,6] == "A"){
A[i,] = as.matrix(mets[i,])
}
}
print(A)
You may wanna try to specify ncol=dim(mets)[2] to make sure you are providing same number of inputs to fill the matrix.

Construct a list of matrices from a list of vectors

I'm trying to use lapply to transform a list of vectors into a list of matrices.
I'm afraid I haven't been able to find anything to help in my searches!
I know this could be resolved by looping over the length of the list but I've been trying to change my code to avoid loops wherever possible.
The real world example has a much larger span than the toy example below so I'm trying to write efficient code.
SparseIndicies <- matrix(0, 100, 4)
SparseIndicies[, 1] <- rep(1:5, 20) #Assign a group (this is what we want to partition on)
SparseIndicies[, 2] <- sample(1:10, 100, replace=TRUE)
SparseIndicies[, 3] <- sample(1:10, 100, replace=TRUE)
SparseIndicies[, 4] <- runif(100, 0, 1)
#Above replicates my data structure, albeit randomly
TransitionIndicies <- split(SparseIndicies, as.factor(SparseIndicies[, 1]))
#We now have a list of transition values for each 'group' - though this is now in vector format
#We can do it explicitly for each list item
FirstTransitionIndicies <- matrix(TransitionIndicies[[1]], nrow=20, ncol=4)
#The below falls over with:
#Error in match.fun(FUN) :
# 'matrix(TransitionIndicies, nrow = 20, ncol = 4)' is not a function, character or symbol
NewTransitionIndicies <- lapply(TransitionIndicies, matrix(TransitionIndicies, nrow=20, ncol=4))
FYI: The 2nd and 3rd column of the above is used to create a sparse matrix with the value of the fourth column.
FirstTransitionMatrix <- sparseMatrix(FirstTransitionIndicies[, 2], FirstTransitionIndicies[, 3], x=FirstTransitionIndicies[, 4])
Many thanks for any help you can offer, or resources you can point me towards!
I think you want to use:
lapply(TransitionIndicies, function(x) matrix(x, nrow=20, ncol=4))
You weren't specifying a function to lapply, here the error message was pretty informative.
You could also use (less explicitly):
lapply(TransitionIndicies, matrix, nrow=20, ncol=4)

Operating on multiple matrices in a for loop using R

I have 1000 matrices named A1, A2, A3,...A1000.
In a for loop I would like to simply take the colMeans() of each matrix:
for (i in 1:1000){
means[i,]<-colMeans(A1)
}
I would like to do this for each matrix Ax. Is there a way to put Ai instead of A1 in the for loop?
So, one way is:
for (i in 1:1000){
means[i,]<-colMeans(get(paste('A', i, sep = '')))
}
but I think that misses the point of some of the comments, i.e., you probably had to do something like this:
csvs = lapply(list.files('.', pattern = 'A*.csv'), function(fname) {
read.csv(fname)
})
Then the answer to your question is:
means = lapply(csvs, colMeans)
I don't completely understand, but maybe you have assigned each matrix to a different variable name? That is not the best structure, but you can recover from it:
# Simulate the awful data structure.
matrix.names<-paste0('A',1:1000)
for (name in matrix.names) assign(name,matrix(rnorm(9),ncol=3))
# Pull it into an appropriate list
list.of.matrices<-lapply(matrix.names,get)
# Calculate the column means
column.mean.by.matrix<-sapply(list.of.matrices,colMeans)
You initial question asks for a 'for loop' solution. However, there is an easy way to get the desired
result if we use an 'apply' function.
Perhaps putting the matrices into a list, and then applying a function would prove worthwhile.
### Create matrices
A1 <- matrix(1:4, nrow = 2, ncol = 2)
A2 <- matrix(5:9, nrow = 2, ncol = 2)
A3 <- matrix(11:14, nrow = 2, ncol = 2)
### Create a vector of names
names <- paste0('A', 1:3)
### Create a list of matrices, and assign names
list <- lapply(names, get)
names(list) <- names
### Apply the function 'colMeans' to every matrix in our list
sapply(list, colMeans)
I hope this was useful!
As others wrote already, using a list is perhaps your best option. First you'll need to place your 1000 matrices in a list, most easily accomplished using a for-loop (see several posts above). Your next step is more important: using another for-loop to calculate the summary statistics (colMeans).
To apply a for-loop through an R object, in general you can do one of the two options:
Loop over by indices: for example:
for(i in 1:10){head(mat[i])} #simplistic example
Loop "directly"
for(i in mat){print(i)} #simplistic example
In the case of looping through R lists, the FIRST option will be much easier to set up. Here is the idea adapted to your example:
column_means <- rep(NA,1000) #empty vector to store column means
for (i in 1:length(list_of_matrices)){
mat <- list_of_matrices[[i]] #temporarily store individual matrices
##be sure also to use double brackets!
column_means <- c(column_means, colMeans(mat))

Resources