R applying a function to a sub-matrix [duplicate] - r

If I have an array A
A <- array(0, c(4, 3, 5))
for(i in 1:5) {
set.seed(i)
A[, , i] <- matrix(rnorm(12), 4, 3)
}
and if I have matrix B
set.seed(6)
B <- matrix(rnorm(12), 4, 3)
The code to subtract B from the each matrix of the array A would be:
d<-array(0, c(4,3,5))
for(i in 1:5){
d[,,i]<-A[,,i]-B
}
However, what would be the code to perform the same calculation using a function from "apply" family?

This is what sweep is for.
sweep(A, 1:2, B)

Maybe not very intuitive:
A[] <- apply(A, 3, `-`, B)

Because you are looping on the last array dimension, you can simply do:
d <- A - as.vector(B)
and it will be much faster. It is the same idea as when you subtract a vector from a matrix: the vector is recycled so it is subtracted to each column.

Related

Is there another way to write the following function without the for loop in R?

I am trying to write the following function without the for loop. Note that I am trying to replicate the function diag().
selfdiag <- function(a) {
j <- c()
for (i in 1:ncol(a)) {
j[i] <- a[i, i]
}
return(j)
}
Consider that:
mat <- matrix(rnorm(4), ncol = 2)
The function selfdiag() should create the same result as diag().
Thanks for any help on this.
You can create a data frame with the row and column indices for the diagonal and use it to extract the diagonal values from the matrix.
mat <- matrix(rnorm(4), ncol = 2)
The diag() way to do it -
diag(mat)
[1] -0.5004046 -0.8785558
The other way to do it -
rows_cols <- data.frame(rows = c(1:ncol(mat)), cols = c(1:ncol(mat)))
mat2 <- mat[as.matrix(rows_cols)]
mat2
[1] -0.5004046 -0.8785558
Hope this helps!

How to rank a vector inside a matrix? in R

I have made a matrix where each element in the matrix is a vector of two numbers.
Now I want to rank all the vectors inside, so I get the rank of the vectors as the new vector elements of the matrix.
Here is an example of the code:
listwvectors <- vector("list")
t=1
for (i in 1:3) {
for (j in 1:5) {
listwvectors[[t]] <- c(i,j)
t=t+1
}
}
print(listwvectors)
testmatrix <- matrix(data=listwvectors, nrow=5, ncol=3)
print(testmatrix)
rank(testmatrix[1,1])
The last part ("rank(testmatrix[1,1])") just give 1.
Why is that? I want it to print the ranked vector.
So in fact, I want to make a new matrix that has the same mode as the testmatrix but the vectors inside is the ranked vectors of the testmatrix.
Hope you understand what I am trying to ask.
Thanks in advance!:)
minimal example data:
m <- matrix(list(c(1,3), c(2,1), c(2,2), c(1,2)), ncol=2)
[, 1] [, 2]
[1, ] c(1, 3) c(2, 2)
[2, ] c(2, 1) c(1, 2)
Solution 1 using apply (returns '3d matrix'):
apply(apply(m, c(1,2), function(x) rank(x[[1]]))
Solution 2 using loop (returns '2d matrix' of lists):
result <- m # copy original matrix as template to recieve rankings
for (i in seq_along(m[, 1])) {
for (j in seq_along(m[1, ])) {
result[i, j][[1]] <- rank(m[i, j][[1]])
}
}
since there is only one vector inside a matrix, you can use rank(my_matrix)

What is the alternative instruction instead of writing many nested for loop in R?

I have 29 matrix. I need to write 29 nested loops and in the last loop I should call a function on the 29-word string. But writing 29 loops is time consuming. Also, I have to repeat this procedure in another R code. I'm looking for an alternative way to implement these loops.
The code for what I explained is as follows. m1 to m29 are matrix and make_rule_antc is the function that I call on each element of the matrix:
for (i1 in 1:nrow(m1)){
for (i2 in 1:nrow(m2)){
for (i3 in 1:nrow(m3)){
.
.
.
for (i29 in 1:nrow(m29)){
make_rule_antc(m1[i1,],m2[i2,],m3[i3,],...,m29[i29,])
}
}
}
}
I think it should be something like this:
m1=matrix(c(1,2,3,4), nrow = 2)
m2=matrix(c(1,2,3,4), nrow = 2)
m3=matrix(c(1,2,3,4), nrow = 2)
ms=list(m1,m2,m3)
idx=expand.grid(lapply(ms,FUN=function(x) seq(1,nrow(x))))
body=function(x) {
arglist=list()
for (i in 1:length(x))
arglist[[i]]=ms[[i]][x[i],]
do.call(make_rule_antc, arglist)
}
apply(idx,MARGIN = 1, FUN=body)
#cyberj0g solution can be simplified to this
m1 <- matrix(c(1,2,3,4), nrow = 2)
m2 <- matrix(c(1,2,3,4), nrow = 2)
m3 <- matrix(c(1,2,3,4), nrow = 2)
ms <- list(m1, m2, m3)
rows <- sapply(ms, nrow)
combination <- expand.grid(lapply(rows, seq_len))
apply(combination, 1, function(x){
do.call(make_rule_antc, as.list(x))
})

Variable matrix index and row/column as indices in a single function argument

How to handle a variable matrix index and row/column as indices in a single function argument?
m <- matrix(1:9, 3)
fn <- function(m, subsetArg) {
stopifnot(m[subsetArg] == 6)
}
I'd like to be able to use both situations:
a <- matrix(FALSE, 3, 3)
a[2,3] <- TRUE
# yielding
# F F F
# F F T
# F F F
fn(m, subsetArgument = a) # works
and
fn(m, subsetArgument = tuple(2,3)) # <- does not work logically
Note that I would also be after using a range, for example tuple(2, 1:3)
I understand this could be done very explicitly by testing for either 1 or 2 variables given, but I feel there might be an easier way.
Just slurp all the arguments up and pass them into a call to [:
fn <- function(...) {
stopifnot(do.call(`[`, list(...)) == 6)
}
Everything in R is a function, including subsetting :-)
You can subset a matrix using an integer matrix. For example, instead of
m <- matrix(1:9, 3)
fn <- function(m, subsetArg) {
(m[subsetArg])
}
a <- matrix(FALSE, 3, 3)
a[2,3] <- TRUE
fn(m,subsetArg=a)
You could simply write:
n <- matrix(ncol=2, byrow=TRUE, c(2,3))
m[n]
Which would also work in your function, and returns the same result:
fn(m,subsetArg=n)
If you create your index matrix correct you can get the result that you're looking for in the tuple example:
n.tuple <- as.matrix(expand.grid(x=2, y=1:3))
m[n.tuple]
Of course you could write a tuple function which does it for you, which would work as expected:
tuple <- function(x,y) {
as.matrix(expand.grid(x=x, y=y))
}
fn(m, subsetArg = tuple(2,3)) # 8
fn(m, subsetArg = tuple(2,1:3)) # 2 5 8

sweeping out colMeans and rowMeans

To sweep out colMeans, rowMeans and mean from columns, rows and observations respectively I use the following code:
a <- matrix(data=seq(from=2, to=60, by=2), nrow=6, ncol=5, byrow=FALSE)
b <- matrix(data=rep(colMeans(a), nrow(a)), nrow=nrow(a), ncol=ncol(a), byrow=TRUE)
c <- matrix(data=rep(rowMeans(a), ncol(a)), nrow=nrow(a), ncol=ncol(a), byrow=FALSE)
d <- matrix(data=rep(mean(a), nrow(a)*ncol(a)), nrow=nrow(a), ncol=ncol(a), byrow=FALSE)
e <- a-b-c-d
colMeans can be sweep out by using this command
a1 <- sweep(a, 2, colMeans(a), "-")
Is there any single command to sweep out colMeans, rowMeans and mean? Thanks in advance.
What do you think eshould look like in this example? Perhaps your line should be e <- a-b-c+d so that e has zero mean.
The following code produces the same result as your calculation using b, c, and d (with your arithmetic progression example, a matrix of 0s). Change +to - if you insist.
e <- t(t(a) - colMeans(a)) - rowMeans(a) + mean(a)
Not that I know of, but why not just write your own? It's only four lines:
meanSweep <- function(x){
tmp <- sweep(x,2,colMeans(x),"-")
tmp <- sweep(tmp,1,rowMeans(x),"-")
tmp <- tmp - mean(x)
tmp
}
all.equal(e,meanSweep(a))
[1] TRUE

Resources