R: Using Mapply to avoid loop - r

I have following code which I perform with for loop to generate a 3D array "newarr".
n1<-c(1,2,3,4,5)
n2<-c(3,4,5,6,7)
n3<- c(4,5,6,7,8)
afun <- function(y,p,q,r){
calc=1/(1+(((y-p)/q)^(2*r)))
return(calc)
}
newarr<- array(dim = c(4,5,5))
Amat<-matrix(data=c(1:10,NA,NA,NA,NA,15:20),nrow = 4,ncol = 5)
Bmat<-matrix(data=c(1:6,NA,NA,NA,NA,11:20),nrow = 4,ncol = 5)
Qmat<- +(!is.na(Amat) & !is.na(Bmat))
for(i in 1:5){
res<-afun(Amat,n1[i],n2[i],n3[i])
newarr[,,i]<- res
}
I want to use Mapply (or any apply function) instead of for loop.
arr2 <- array((mapply(function(x,y,n1,n2,n3) if(x==1) afun(y,n1,n2,n3) else 0,Qmat,Amat,n1,n2,n3)),c(4,5,5))
The following code seems to help but without condition as described further:
newarr <- array(mapply(afun, n1,n2,n3, MoreArgs = list(y=Amat)), c(4,5,5))
I want to include a condition by using Qmat (a 4x5 matrix with 0 and 1), so that when '0' is observed, no operation should be performed and return '0'value to fill matrix. For 1s in Qmat, perform 'afun' function and return the value to "newarr" to form a 3D matrix.
Thanks for the help!!

This will give you the desired result:
newarr <- array(mapply(afun, n1,n2,n3, MoreArgs = list(y=Amat)), c(4,5,5))
this is using the implicit SIMPLIFY=TRUE of mapply(). With SIMPLIFY=TRUE each result is reduced to a vector. (a matrix is a vector with a dimension attribute)
Another variant is
array(unlist(mapply(afun, n1,n2,n3, MoreArgs = list(y=Amat), SIMPLIFY = FALSE)), c(4,5,5))
here you will get a list of matrices as result from mapply(). You have to unlist.

Related

T test for two lists of matrices

I have two lists of matrices (list A and list B, each matrix is of dimension 14x14, and list A contains 10 matrices and list B 11)
and I would like to do a t test for each coordinate to compare the means of each coordinate of group A and group B.
As a result I would like to have a matrix of dimension 14x14 which contains the p value associated with each t test.
Thank you in advance for your answers.
Here's a method using a for loop and then applying the lm() function.
First we'll generate some fake data as described in the question.
#generating fake matrices described by OP
listA <- vector(mode = "list", length = 10)
listB <- vector(mode = "list", length = 10)
for (i in 1:10) {
listA[[i]] <- matrix(rnorm(196),14,14,byrow = TRUE)
}
for (i in 1:11) {
listB[[i]] <- matrix(rnorm(196),14,14,byrow = TRUE)
}
Then we'll unwrap each matrix as described by dcarlson in a for loop.
Unwrapped.Mats <- NULL
for (ID in 1:10) {
unwrapped <- as.vector(as.matrix(listA[[ID]])) #Unwrapping each matrix into a vector
withID <- c(ID, "GroupA", unwrapped) #labeling it with ID# and which group it belongs to
UnwrappedCorMats <- rbind(Unwrapped.Mats, withID)
}
for (ID in 1:11) {
unwrapped <- as.vector(as.matrix(listB[[ID]]))
withID <- c(PID, "GroupB", unwrapped)
UnwrappedCorMats <- rbind(UnwrappedCorMats, withID)
}
Then write and apply a function to run lm(). lm() is statistically equivalent to an unpaired t-test in this context but I'm using it to be more easily adapted into a mixed effect model if anyone wants to add mixed effects.
UnwrappedDF <- as.data.frame(UnwrappedCorMats)
lmPixel2Pixel <- function(i) { #defining function to run lm
lmoutput <- summary(lm(i ~ V2, data= UnwrappedDF))
lmoutputJustP <- lmoutput$coefficients[2,4] #Comment out this line to return full lm output rather than just p value
}
Vector_pvals <- sapply(UnwrappedDF[3:length(UnwrappedDF)], lmPixel2Pixel)
Finally we will reform the vector into the same shape as the original matrix for more easily interpreting results
LM_mat.again <- as.data.frame(matrix(Vector_pvals, nrow = nrow(listA[[1]]), ncol = ncol(listA[[1]]), byrow = T))
colnames(LM_mat.again) <- colnames(listA[[1]]) #if your matrix has row or column names then restoring them is helpful for interpretation
rownames(LM_mat.again) <- colnames(listB[[1]])
head(LM_mat.again)
I'm sure there are faster methods but this one is pretty straight forward and I was surprised there weren't answers for this type of operation yet

R: Apply over every column of nXm matrix, return n*n*m array

What is the appropriate function to apply a function that returns an n*n matrix, over every column of a matrix/nXm array, and get back an nXnXm array? I can get it to work with a list:
dm <- structure(c(0.205292439079469, 0.222642769676055, 0.222786614980172,
0.210917067409095, 0.123955673451174, 0.10591537361648, 0.0887665882561804,
0.0725263089185602, 0.174088645938512, 0.171936521036433, 0.159619467190219,
0.143492610130578, 0.23303504847129, 0.269389294469438, 0.279103519495381,
0.240824583373471, 0.192637398624569, 0.201551950015116, 0.195748345926477,
0.181448686311511), .Dim = 4:5)
sapply(1:ncol(dm), function(x){dm[, x] %*% t(dm[, x])^-1}, simplify = F)
Thank you!
Use simplify = "array" instead of simplify = F.
sapply(1:ncol(dm), function(x){dm[, x] %*% t(dm[, x])^-1}, simplify = "array")

Function mapped to reduce function to concatenate vectors together

I'm trying to write a function that maps a function to reduce to concatenate a list of vectors together into 1 with the very first entry and the very last entry.
For example,
reduce(list(1:10, 11:20, 21:100), r_cat, .init = NULL)
should return a vector equal to
1:100
This is what I have so far.
r_cat = function(x, y) {
out <- y[[1]]
for(i in seq(2, length(y))) {
out <- x(out, y[[i]])
}
out
}
Any thoughts?
No need to write a new function, unlist solves your problem:
List <- list(1:10, 11:20, 21:100)
unlist(List)
If you want to use Reduce from R base, then you can use c
Reduce("c", List)
You can also get the same result plugging c into reduce from purrr
library(purrr)
reduce(List, c)

R - how do I run each function in a list of functions with parameters given by a vector

Suppose I have a list of functions and a vector of parameter values:
functions <- list(a = function(x) x *2, b = function(x) x*3, c = function(x) x * 4)
paramVector <- c(2, 2, 1)
Now I want the following functionality of calling each function with the corresponding parameter and collating the result into a vector:
result <- c()
for (idx in 1:length(functions)) {
result[idx] <- functions[[idx]](paramVector[idx])
}
result
Is there a way to do this without the for loop?
To iterate over the functions and paramVector objects at the same time, use Map. For example
Map(function(f,p) f(p), functions, paramVector)
Note that Map() always returns a list. You can also use mapply() which will attempt to simplify to a vector
mapply(function(f,p) f(p), functions, paramVector)

Create a function that takes in a vector and returns a matrix in R

I am trying to create a function that will take in a vector k and return to me a matrix with dimensions length(distMat[1,]) by length(k). distMat is a huge matrix and indSpam is a long vector. In particular to my situation, length(distMat[1,]) is 2412. When I enter in k as a vector of length one, I get a vector of length 2412. I want to be able to enter in k as a vector of length two and get a matrix of 2412x2. I am trying to use a while loop to let it go through the length of k, but it only returns to me a vector of length 2412. What am I doing wrong?
predNeighbor = function(k, distMat, indSpam){
counter = 1
while (counter<(length(k)+1))
{
preMatrix = apply(distMat, 1, order)
orderedMatrix = t(preMatrix)
truncate = orderedMatrix[,1:k[counter]]
checking = indSpam[truncate]
checking2 = matrix(checking, ncol = k[counter])
number = apply(checking2, 1, sum)
return(number[1:length(distMat[1,])] > (k[counter]/2))
counter = counter + 1
}
}
I am trying to create a function that will take in a vector k and return to me a matrix with dimensions length(distMat[1,]) by length(k)
Here's a function that does this.
foo <- function(k, distMat) {
return(matrix(0, nrow = length(distMat[1, ]), ncol = length(k)))
}
If you have other requirements, please describe them in words.
Based on your comment, I think I understand better your goal. You have a function that returns a vector of length k and you want to save it's output as rows in a matrix. This is a pretty common task. Let's do a simple example where k starts out as 1:10, and say we want to add some noise to it with a function foo() and see how the rank changes.
In the case where the input to the function is always the same, replicate() works very well. It will automatically put everything in a matrix
k <- 1:10
noise_and_rank <- function(k) {
rank(k + runif(length(k), min = -2, max = 2))
}
results <- replicate(n = 8, expr = {noise_and_rank(k)})
In the case where you want to iterate, i.e., the output from the one go is the input for the next, a for loop is good, and we just pre-allocate a matrix with 0's, to fill in one column/row at a time
k <- 1:10
n.sim <- 8
results <- matrix(0, nrow = length(k), ncol = n.sim)
results[, 1] <- k
for(i in 2:n.sim) {
results[, i] <- noise_and_rank(results[, i - 1])
}
What your original question seems to be about is how to do the pre-allocation. If the input is always the same, using replicate() means you don't worry about it. If the input is is different each time, then pre-allocate using matrix(), you don't need to write any special function.

Resources