Efficiently substract from matrix columnwise - r

I have a rather simple problem and was wondering whether some of you guys know a very efficient (=fast) solution for this:
I have two matrices mat and arr and want to accomplish the following: Take every column of arr and substract it from mat. Then take the logarithm of one minus the absolute value of the difference. That's it. Right now, I'm using sapply (see below), but I'm pretty sure that it's possible to do it faster (maybe using sweep?)
Code:
mat <- matrix(.3, nrow=10, ncol = 4)
arr <- matrix(.1, nrow=10, ncol = 10000)
i <- ncol(arr)
result <- sapply(1:i, function(ii) (log(1-abs(mat-arr[,ii]))))
Thanks for any ideas!

We could replicate and then do a difference
result2 <- matrix(log(1- abs(rep(mat, ncol(arr)) -
rep(arr, ncol(mat)))), ncol = i)
identical(result, result2)
#[1] TRUE

Related

Is there a native R syntax to extract rows of an array?

Imagine I have an array in R with N dimensions (a matrix would be an array with 2 dimensions) and I want to select the rows from 1 to n of my array. I was wondering if there was a syntax to do this in R without knowing the number of dimensions.
Indeed, I can do
x = matrix(0, nrow = 10, ncol = 2)
x[1:5, ] # to take the 5 first rows of a matrix
x = array(0, dim = c(10, 2, 3))
x[1:5, , ] # to take the 5 first rows of a 3D array
So far I haven't found a way to use this kind of writing to extract rows of an array without knowing its number of dimensions (obviously if I knew the number of dimensions I would just have to put as many commas as needed). The following snippet works but does not seem to be the most native way to do it:
x = array(0, dim = c(10, 2, 3, 4)
apply(x, 2:length(dim(x)), function(y) y[1:5])
Is there a more R way to achieve this?
Your apply solution is the best, actually.
apply(x, 2:length(dim(x)), `[`, 1:5)
or even better as #RuiBarradas pointed out (please vote his comment too!):
apply(x, -1, `[`, 1:5)
Coming from Lisp, I can say, that R is very lispy.
And the apply solution is a very lispy solution.
And therefore it is very R-ish (a solution following the functional programming paradigm).
Function slice.index() is easily overlooked (as I know to my cost! see magic::arow()) but can be useful in this case:
x <- array(runif(60), dim = c(10, 2, 3))
array(x[slice.index(x,1) %in% 1:5],c(5,dim(x)[-1]))
HTH, Robin

In R, is it possible to use a pair, tuple or equivalent in a matrix?

I am trying to create a matrix of coordinates(indexes) that I randomly pick one from using the sample function. I then use these to select a cell in another matrix. What is the best way to do this? The trouble is how to store these integers in the matrix so that they are easy to separate. Right now I have them stored as strings with a comma, that I then split. Someone suggested I use a pair, or a string, but I cannot seam to get these to work with a matrix. Thanks!
EDIT:What i currently have looks like this (changed a little to make sense out of context):
probs <- matrix(c(0,0,0.6,0,0,
0,0.7,1,0.7,0,
0.6,1,0,1,0.6,
0,0.7,1,0.7,0,
0,0,0.6,0,0),5,5)
cordsMat <- matrix("",5,5)
for (x in 1:5){
for (y in 1:5){
cordsMat[x,y] = paste(x,y,sep=",")
}
}
cords <- sample(cordsMat,1,,probs)
cordsVec <- unlist(strsplit(cords,split = ","))
cordX <- as.numeric(cordsVec[1])
cordY <- as.numeric(cordsVec[2])
otherMat[cordX,cordY]
It sort of works but i would also be interested for a better way, as this will get repeated a lot.
If you want to set the probabilities it can easily be done by providing it to sample
# creating the matrix
matrix(sample(rep(1:6, 15:20), 25), 5) -> other.mat
# set the probs vec
probs <- c(0,0,0.6,0,0,
0,0.7,1,0.7,0,
0.6,1,0,1,0.6,
0,0.7,1,0.7,0,
0,0,0.6,0,0)
# the coordinates matrix
mat <- as.matrix(expand.grid(1:nrow(other.mat),1:ncol(other.mat)))
# sampling a row randomly
sample(mat, 1, prob=probs) -> rand
# getting the value
other.mat[mat[rand,1], mat[rand,2]]
[1] 6

In R, faster way than for loop or apply

For these two matrices, I want to find the product of the matrix X and the row of Q and apply ifelse function to see if the product is greater than zero.
n1=1000, m=10000
X=cbind(rnorm(n1),rbinom(n1))
Q=matrix(rnorm(2*m), ncol=2)
To do this, I tried for loop and apply function in the following.
D=10000
ind_beta=matrix(0,n1,D)
for (l in 1:D){
ind[,l]=as.vector(ifelse(X%*%Q[l,]>=0,1,0))
}
and
ind=apply(Q,1,function(x){ifelse(X%*%Q>=0,1,0)})
Both codes give the same result, but it is really time consuming.
Is there any way to make this fast? Thanks in advance.
How about:
Make data (reproducibly):
set.seed(101)
n1=1000; m=10000
X=cbind(rnorm(n1),rbinom(n1,size=1,prob=0.6))
Q=matrix(rnorm(2*m), ncol=2)
Your way takes about 2.5 seconds:
system.time(ind <- apply(Q,1,function(x){ifelse(X%*%x>=0,1,0)}))
This takes about 0.3 seconds:
system.time({
XQ <- X %*% t(Q)
ind2 <- matrix(as.numeric(XQ>=0),nrow(XQ))
})
Results match:
all.equal(ind,ind2) ## TRUE

Setting NA in a matrix using another logical matrix

I just saw what seemed like a perfectly good question that was deleted and since like the original questioner I couldn't find a duplicate, I'm posting again.
Assume that I have a simple matrix ("m"), which I want to index with another logical matrix ("i"), keeping the original matrix structure intact. Something like this:
# original matrix
m <- matrix(1:12, nrow = 3, ncol = 4)
# logical matrix
i <- matrix(c(rep(FALSE, 6), rep(TRUE, 6)), nrow = 3, ncol = 4)
m
i
# Desired output:
matrix(c(rep(NA,6), m[i]), nrow(m), ncol(m))
# however this seems bad programming...
Using m[i] returns a vector and not a matrix. What is the correct way to achieve this?
The original poster added a comment saying he'd figured out a solution, then almost immediately deleted it:
m[ !i ] <- NA
I had started an answer that offered a slightly different solution using the is.na<- function:
is.na(m) <- !i
Both solutions seem to be reasonable R code that rely upon logical indexing. (The i matrix structure is not actually relied upon. A vector of the proper length and entries would also have preserved the matrix structure of m.)
Both solutions provide above works and are fine. Here is another solution to produce a new matrix, without modifying the previous one. Make sure that your matrix of logical values are well store as logical, and not as character.
vm <- as.vector(m)
vi <- as.vector(i)
new_v <- ifelse(vi, vm, NA)
new_mat <- matrix(new_v, nrow = nrow(m), ncol=ncol(m))

How to square matrix elements in R using loops and apply function

I have a 3x3 matrix that I have made in R. I am being asking to square all the numbers in the matrix. First using loops and then using the apply function. I have done the following already.
myMatrix = matrix ( c(1,2,3,4,5,6,7,8,9), nrow=3, ncol=3)
So that gives me my matrix. Then I used this to square them
myMatrix * myMatrix ##don't know how to make a loop to do this
And finally my attempt to use the apply() function to do the same thing
apply(myMatrix, c(1,2), exp) ##this gave me numbers that didnt look correct
Any help in the right direction would be very nice.
Thanks
The accepted answer is highly inefficient; Instead one should realize that the "^" operator works in an element wise fashion and use:
sqrdMtx <- myMatrix^2
The "^" operator is not matrix power when its arguments are matrices. For that you need matpow in pkg:expm.
As some comments mentioned, these are not the best approach to squaring a matrix. But since you asked...
Using a loop:
myMatrix = matrix ( c(1,2,3,4,5,6,7,8,9), nrow=3, ncol=3)
# empty matrix for the results
squaredMatrix = matrix(nrow=3, ncol=3)
for(i in 1:nrow(myMatrix)) {
for(j in 1:ncol(myMatrix)) {
squaredMatrix[i,j] = myMatrix[i,j]^2
}
}
Edit:
As noted in a comment below, you can also use a single loop:
squaredMatrix = matrix(nrow=3, ncol=3)
for (i in 1:length(myMatrix)) {
squaredMatrix[i] <- myMatrix[i]^2
}
Using the apply function:
squaredMatrix = apply(myMatrix, c(1,2), function(x) x^2)

Resources