R nested for loops - r

I am trying to do a nested for loop in R and am a bit confused on how to make it work. I want to assign rows 1:4 of matrix m based upon a function of i. Below I have generalization of my current code. I believe I need to double loop as my actual code for i depends on the values 5, 10, 15, 25.
f <- function()
m <- matrix(nrow = 4)
for (i in c(5, 10, 15, 25)) {
for (j in c(1:4)) {
m[j,1] <- f(i)
}
}
which results in:
> m
[,1]
[1,] f(25)
[2,] f(25)
[3,] f(25)
[4,] f(25)
My desired output is below and I'm not sure how to do the loop to produce these results.
> m
[,1]
[1,] f(5)
[2,] f(10)
[3,] f(15)
[4,] f(25)

I think doing a nested for-loop would be hard so I ended up doing:
f <- function()
sapply(c(5, 10, 15, 25), f) %>%
matrix()

Related

Calculating exp() of each element in matrix using R

how can I take exp() of each element in a matrix? I have mymatrix = matrix(c(2, 4, 3, 1, 5, 7), 3,2) and tried using res<-expm(mymatrix) but it requires mymatrix to be square. Is there another way to calculate each element so
res is matrix(c(exp(2), exp(4), exp(3), exp(1), exp(5), exp(7), 3,2) ?
res <- mymatrix
res [] <- exp(res)
> res
[,1] [,2]
[1,] 7.389056 2.718282
[2,] 54.598150 148.413159
[3,] 20.085537 1096.633158
Here you go.

How to calculate correlation between matrices with different column dimention in R

I have two matrices with same number of rows and different number of columns as:
mat1 <- matrix(rnorm(20), 4, 5)
mat2 <- matrix(rnorm(12), 4, 3)
Since i have the same number of rows I want to calculate the following correlation between the columns of the matrices:
cor.test(mat1[,1], mat2[,1])
cor.test(mat1[,1], mat2[,2])
cor.test(mat1[,1], mat2[,3])
cor.test(mat1[,2], mat2[,1])
cor.test(mat1[,2], mat2[,2])
cor.test(mat1[,2], mat2[,3])
...........
...........
cor.test(mat1[,5], mat2[,3])
for(i in 1:5){
for(j in 1:3){
pv[i,j] <- cor.test(mat1[, i], mat2[ , j])$p.value
}
}
At the end I want a matrix(5 * 3) or vector containing the correlation values, can anyone help?
Can i use this to return both p.value and estimate?
FUN <- function(x, y) {
res <- cor.test(x, y, method="spearman", exact=F)
return(list(c = res$estimate, p = res$p.value))
}
r1 <- outer(colnames(mat1), colnames(mat2), Vectorize(function(i,j) FUN(mat1[,i], mat2[,j])$p))
r2 <- outer(colnames(mat1), colnames(mat2), Vectorize(function(i,j) FUN(mat1[,i], mat2[,j])$c))
Thank you.
Why don't you just use cor function to calculate the pearson correlation?
seed(1)
mat1 <- matrix(rnorm(20), 4, 5)
mat2 <- matrix(rnorm(12), 4, 3)
cor(mat1, mat2)
[,1] [,2] [,3]
[1,] 0.4406765 -0.70959590 0.10731768
[2,] -0.2566199 -0.01588993 -0.63630159
[3,] -0.9813313 0.85082165 -0.77172317
[4,] 0.6121358 -0.38564314 0.87077092
[5,] -0.6897573 0.66272015 -0.08380553
To double check,
> col_1 <- 3
> col_2 <- 2
# all.equal is used to compare numeric equality where `==` is discouraged
> all.equal(cor(mat1, mat2)[col_1, col_2], cor(mat1[,col_1], mat2[,col_2]))
[1] TRUE
They are equal!
An alternative, slightly easier to understand than loops in my opinion:
sapply(
data.frame(mat1),
function(x) Map(function(a,b) cor.test(a,b)$p.value,
list(x),
as.data.frame(mat2))
)
Result:
# X1 X2 X3 X4 X5
#[1,] 0.7400541 0.8000358 0.5084979 0.4441933 0.9104712
#[2,] 0.2918163 0.2764817 0.956807 0.6072979 0.4395218
#[3,] 0.2866105 0.4095909 0.5648188 0.1746428 0.9125866
I supose you would like to do it without for's. With base stuff, here is the double apply aproach:
apply(mat1, 2, function(col_mat1){
apply(mat2, 2, function(col2, col1) {
cor.test(col2, col1)$p.value
}, col1=col_mat1)
})
The outter apply iterates at mat1 columns and serves one side of cor.test(). The inner one does the same, but now fills the second side of cor.test(). In practie, apply is replacing the for's.
I think all you need is to define your matrix first
mat_cor <- matrix(nrow=ncol(mat1), ncol=ncol(mat2))
for(i in 1:5)
{
for(j in 1:3)
{
mat_cor[i,j] <- cor.test(mat1[, i], mat2[ , j])$p.value
}
}
Output
mat_cor
[,1] [,2] [,3]
[1,] 0.9455569 0.8362242 0.162569342
[2,] 0.7755360 0.9849619 0.775006329
[3,] 0.8799139 0.8050564 0.001358697
[4,] 0.1574388 0.1808167 0.618624825
[5,] 0.8571844 0.8897125 0.879818822
You can try with something like this
pv <- c()
for(i in 1:dim(mat1)[2]){
for(j in 1:dim(mat2)[2]){
pv <-c(c, cor.test(mat1[, i], mat2[ , j])$estimate)
}
}
dim(pv) <- c(dim(mat1)[2], dim(mat2)[2])

Finding dimensional index in a multi-dimensional array in R

Am looking at say 3-dimensional array M: M<-dim(3,3,3)
I want to find an efficient way to populate M with the following rule:
M[i,j,k] = i/10 + j^2 + sqrt(k),
ideally without having to write a loop with a for statemenet.
For clarification, there is a simple way to accomplishing this if M were 2-dimensional. If i wanted to have
M[i,j] = i/10 + j^2,
then i could just do
M<-row(M)/10 + col(M)*col(M)
Is there something equivalent for 3-or-higher dimensional arrays?
#James's answer is better, but I think the narrow answer to your question (multidimensional equivalent of row()/col()) is slice.index ...
M<- array(dim=c(3,3,3))
slice.index(M,1)/10+slice.index(M,2)^2+sqrt(slice.index(M,3))
It would be a good idea if someone (I or someone else) posted a suggestion on the r-devel list to make slice.index a "See also" entry on ?row/?col ...
Alternatively (similar to #flodel's new answer):
d <- do.call(expand.grid,lapply(dim(M),seq)) ## create data.frame of indices
v <- with(d,Var1/10+Var2^2+sqrt(Var3)) ## default names Var1, ... Varn
dim(v) <- dim(M) ## reshape into array
How about using nested outers?
outer(1:3/10,outer((1:3)^2,sqrt(1:3),"+"),"+")
, , 1
[,1] [,2] [,3]
[1,] 2.1 5.1 10.1
[2,] 2.2 5.2 10.2
[3,] 2.3 5.3 10.3
, , 2
[,1] [,2] [,3]
[1,] 2.514214 5.514214 10.51421
[2,] 2.614214 5.614214 10.61421
[3,] 2.714214 5.714214 10.71421
, , 3
[,1] [,2] [,3]
[1,] 2.832051 5.832051 10.83205
[2,] 2.932051 5.932051 10.93205
[3,] 3.032051 6.032051 11.03205
You can also use arrayInd:
M <- array(dim = c(3, 3, 3))
foo <- function(dim1, dim2, dim3) dim1/10 + dim2^2 + sqrt(dim3)
idx <- arrayInd(seq_along(M), dim(M), useNames = TRUE)
M[] <- do.call(foo, as.data.frame(idx))
I feel this approach has potential for less typing as the number of dimensions increases.
Doing it from the "ground up" so to speak.
i <- rep(1:3, times=3*3)
j <- rep(1:3 , times= 3, each=3)
k <- rep(1:3 , each= 3*3)
M <- array( i/10 + j^2 + sqrt(k), c(3, 3, 3))
M

How to apply a function to a multidimensional array based on its indices

I have a 4 dimensional array and I want to fill in the slots with values which are a function of the inputs. Through searching the forums here I found that the function "outer" is helpful for 2x2 matrices but cannot be applied to general multidimensional arrays. Is there anything which can achieve this in R more efficiently than the following code ?
K <- array(0,dim=c(2,2,2,2)) #dimensions will be much larger
for(x1 in 1:2)
{
for(y1 in 1:2)
{
for(x2 in 1:2)
{
for(y2 in 1:2)
{
K[x1,y1,x2,y2] <- x1*y2 - sin(x2*y1) #this is just a dummy function.
}
}
}
}
Thank you in advance for any help.
Edit; Here's what I think will be an even faster solution. It assumes that you have predefined K as you offered. It uses the K[] <- construct to insert values calculated on a dataframe environment. Using the square-brackets on the LHS of the assignment preserves K's structure, and I think it is both vectorized and self-documenting:
dfm <- expand.grid(x1=1:2,x2=1:2,y1=1:2,y2=1:2)
K[] <- with(dfm, x1*y2 - sin(x2*y1 ) )
First solution offered:
If you can create a data.frame or matrix that has the indices x1,x2,y1,y2 and the values you can use the: K[cbind(index-vectors)] <- values construction:
mtx<- data.matrix( expand.grid(x1=1:2,x2=1:2,y1=1:2,y2=1:2) )
K[mtx] <- apply(mtx, 1, function(x) x["x1"]*x["y2"] - sin(x['x2']*x['y1']) )
#----------------
> K
, , 1, 1
[,1] [,2]
[1,] 0.158529 0.09070257
[2,] 1.158529 1.09070257
, , 2, 1
[,1] [,2]
[1,] 0.09070257 1.756802
[2,] 1.09070257 2.756802
, , 1, 2
[,1] [,2]
[1,] 1.158529 1.090703
[2,] 3.158529 3.090703
, , 2, 2
[,1] [,2]
[1,] 1.090703 2.756802
[2,] 3.090703 4.756802

Get rank of matrix entries?

Assume a matrix:
> a <- matrix(c(100, 90, 80, 20), 2, 2)
> a
[,1] [,2]
[1,] 100 80
[2,] 90 20
Suppose I want to convert the elements of the matrix to ranks:
>rank.a <- rank(a)
> rank.a
[1] 4 3 2 1
This returns a vector, i.e. the matrix structure is lost. Is it possible to rank a matrix such that the output will be of the form:
[,1] [,2]
[1,] 4 2
[2,] 3 1
An alternative to #EDi's Answer is to copy a and then assign the output of rank(a) directly into the elements of the copy of a:
> a <- matrix(c(100, 90, 80, 20), 2, 2)
> rank.a <- a
> rank.a[] <- rank(a)
> rank.a
[,1] [,2]
[1,] 4 2
[2,] 3 1
That saves you from rebuilding a matrix by interrogating the dimensions of the input matrix.
Note that (as #Andrie mentions in the comments) the copying of a is only required if one wants to keep the original a. The main point to note is that because a is already of the appropriate dimensions, we can treat it like a vector and replace the contents of a with the vector of ranks of a.
why not convert the vector back to a matrix, with the dimensions of the original matrix?
> a <- matrix(c(100, 90, 80, 20, 10, 5), 2, 3)
> a
[,1] [,2] [,3]
[1,] 100 80 10
[2,] 90 20 5
> rank(a)
[1] 6 5 4 3 2 1
> rmat <- matrix(rank(a), nrow = dim(a)[1], ncol = dim(a)[2])
> rmat
[,1] [,2] [,3]
[1,] 6 4 2
[2,] 5 3 1
#Gavin Simpson has a very nice and elegant solution! But there is one caveat though:
The type of the matrix will stay the same or be widened. Mostly you wouldn't notice, but consider the following:
a <- matrix( sample(letters, 4), 2, 2)
rank.a <- a
rank.a[] <- rank(a)
typeof(rank.a) # character
Since the matrix was character to start with, the rank values (which are doubles) got coerced into character strings!
Here's a safer way that simply copies all the attributes:
a <- matrix( sample(letters, 4), 2, 2)
rank.a <- rank(a)
attributes(rank.a) <- attributes(a)
typeof(rank.a) # double
Or, as a one-liner using structure to copy only the relevant attributes (but more typing):
a <- matrix( sample(letters, 4), 2, 2)
rank.a <- structure(rank(a), dim=dim(a), dimnames=dimnames(a))
Of course, dimnames could be left out in this particular case.

Resources