Reputation: 17109
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
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