sooki-sooki
sooki-sooki

Reputation: 69

vectorize this double-loop nest over all matrix elements with 'if ... else ..."

We are given the following R code which iterates through every row and column of matrix A, and if the value is positive, it saves it as is in matrix, and if it is negative, the calculate the exponential value minus 1.

qFunc1 <- function(A) {

if (!is.matrix(A) || !is.numeric(A))
    stop("A must be numeric matrix")

B <- matrix(NA, nrow = nrow(A), ncol = ncol(A))

for (i in seq_len(nrow(A)))
{
    for (j in seq_len(ncol(A)))
    {
        if (!is.na(A[i, j]))
        {
            if (A[i, j] > 0)
                B[i, j] <- A[i, j]
            else
                B[i, j] <- exp(A[i, j]) - 1
        }
    }
}

B
}

This code gives the correct result but we are asked to "vectorize" the loop-nest with a one-liner, which I don't know how. The "if ... else ..." in another "if" makes me struggle.

Thanks for any help in advance!


Note that I am not allowed to use any *apply functions as they are not "vectorized".

Upvotes: 1

Views: 68

Answers (1)

Zheyuan Li
Zheyuan Li

Reputation: 73265

Without the one-liner requirement I would do

B <- A                        ## initialize the output matrix
ind <- (!is.na(A)) & (A <= 0) ## a logical matrix
B[ind] <- exp(A[ind]) - 1     ## update the output matrix

With the one-liner requirement I would do

B <- ifelse((!is.na(A)) & (A <= 0), exp(A) - 1, A)

Here is a quick test.

set.seed(0)
A <- round(matrix(rnorm(25), 5, 5), 2)  ## create a 5 x 5 matrix
A[sample.int(length(A), 5)] <- NA       ## set 5 NA
#      [,1]  [,2]  [,3]  [,4]  [,5]
#[1,]  1.26    NA  0.76 -0.41 -0.22
#[2,] -0.33 -0.93    NA  0.25  0.38
#[3,]  1.33 -0.29 -1.15    NA  0.13
#[4,]  1.27 -0.01 -0.29  0.44  0.80
#[5,]  0.41    NA -0.30    NA -0.06

## use your original function
B1 <- qFunc1(A)

## one-liner "vectorization"
B2 <- ifelse((!is.na(A)) & (A <= 0), exp(A) - 1, A)

## check that they give identical results
all.equal(B1, B2)
#[1] TRUE

Upvotes: 3

Related Questions