We can use pmin
and pmax
after converting the matrix
to data.frame
cbind(min = do.call(pmin, as.data.frame(my_mat)),
max = do.call(pmax, as.data.frame(my_mat)))
# min max
#[1,] -1.3169081 0.2660220
#[2,] -0.6051569 0.5982691
#[3,] -1.7096452 1.5362522
#[4,] -1.4290903 0.6099945
#[5,] -0.6485915 0.8474600
Or use rowMins/rowMaxs
from matrixStats
library(matrixStats)
cbind(min = rowMins(my_mat), max = rowMaxs(my_mat))
# min max
#[1,] -1.3169081 0.2660220
#[2,] -0.6051569 0.5982691
#[3,] -1.7096452 1.5362522
#[4,] -1.4290903 0.6099945
#[5,] -0.6485915 0.8474600
Or more compactly rowRanges
rowRanges(my_mat)
# [,1] [,2]
#[1,] -1.3169081 0.2660220
#[2,] -0.6051569 0.5982691
#[3,] -1.7096452 1.5362522
#[4,] -1.4290903 0.6099945
#[5,] -0.6485915 0.8474600
Or using transmute
library(dplyr)
as.data.frame(my_mat) %>%
transmute(min = pmin(!!! .), max = pmax(!!! .))
# min max
#1 -1.3169081 0.2660220
#2 -0.6051569 0.5982691
#3 -1.7096452 1.5362522
#4 -1.4290903 0.6099945
#5 -0.6485915 0.8474600
Or with rowwise/c_across
library(tidyr)
as.data.frame(my_mat) %>%
rowwise %>%
summarise(out = list(as.list(range(c_across(everything()))))) %>%
unnest_wider(c(out), names_repair = ~ c('min', 'max'))
# A tibble: 5 x 2
# min max
# <dbl> <dbl>
#1 -1.32 0.266
#2 -0.605 0.598
#3 -1.71 1.54
#4 -1.43 0.610
#5 -0.649 0.847
Benchmarks
set.seed(24)
my_mat1 <- matrix(rnorm(5 * 1e7), nrow = 1e7)
system.time(cbind(min = do.call(pmin, as.data.frame(my_mat1)),
max = do.call(pmax, as.data.frame(my_mat1))))
# user system elapsed
# 0.804 0.209 1.009
system.time(rowRanges(my_mat1))
# user system elapsed
# 0.303 0.000 0.303
system.time(apply(my_mat1, 1, range))
# user system elapsed
# 30.373 0.455 31.037
system.time(t(apply(my_mat1, 1, function(x) c(min = min(x), max = max(x)))))
# user system elapsed
# 34.594 0.728 35.240
data
set.seed(24)
my_mat <- matrix(rnorm(25), nrow = 5, dimnames = list(letters[1:5], NULL))