Megatron
Megatron

Reputation: 17109

Multiple replacements within a matrix in a single line in R

Is there a way to do the following replacement in a single line in R? If possible, would it be more/less efficient?

m <- matrix(rnorm(100), ncol=10)

threshold <- 0.5

# Is there a single-line way to do the following in R
m[m < threshold] <- 0
m[m >= threshold] <- 1

I'm wondering if the ifelse() function can accommodate this, in the sense of if < threshold then 0, else 1

Upvotes: 3

Views: 49

Answers (1)

Rich Scriven
Rich Scriven

Reputation: 99391

Since you want a vector of 1s and 0s, you could just reverse your condition, convert the logical values to integer, and create a new matrix with the same dimensions as m.

matrix(as.integer(m >= threshold), nrow(m))

You could also just change the matrix's mode. Normally changing modes would be done in two lines, but you can do it in one with

`mode<-`(m >= threshold, "integer")

Additionally, as @nicola points out, the quick and dirty method is

(m >= threshold) + 0L

By adding the zero integer we coerce the entire matrix to integer.

A couple of others (thanks @Frank):

+(m >= threshold)
m[] <- m >= threshold

So basically, yes. All these perform the task in one line and I can almost guarantee they are all faster than ifelse().

Some benchmarks on a larger matrix (with the replacement method left out):

m <- matrix(rnorm(1e7), ncol=100)
threshold <- 0.5

library(microbenchmark)

microbenchmark(
    matrix = matrix(as.integer(m >= threshold), nrow(m)),
    mode = `mode<-`(m >= threshold, "integer"),
    plus0 = (m >= threshold) + 0L,
    unary = +(m >= threshold)
)

# Unit: milliseconds
#   expr      min       lq     mean   median       uq      max neval
# matrix 295.9292 315.4463 351.9149 351.8144 379.9840 453.4915   100
#   mode 163.2156 172.0180 208.9348 202.8014 232.4525 347.0616   100
#  plus0 170.2059 177.6111 202.3536 192.3516 223.8284 294.8367   100
#  unary 144.0128 150.2696 183.2914 173.4010 203.7955 382.2397   100

For the sake of completeness, here is a benchmark on the replacement method using times = 1.

microbenchmark(
    replacement = { m[] <- m >= threshold },
    times = 1
)
# Unit: milliseconds
#         expr      min       lq     mean   median       uq      max neval
#  replacement 499.4005 499.4005 499.4005 499.4005 499.4005 499.4005     1

Upvotes: 7

Related Questions