mlr-org / mlr3pipelines

Dataflow Programming for Machine Learning in R
https://mlr3pipelines.mlr-org.com/
GNU Lesser General Public License v3.0
132 stars 25 forks source link

perf: improve scale performance by using min/max directly instead of range/diff #776

Closed m-muecke closed 1 month ago

m-muecke commented 2 months ago

Using min/max directly compared to using range seems to be more performant, here a small benchmark and for reference the source code for range and diff explaining why its slower:

variant_a = function(x) {
  rng = range(x, na.rm = TRUE, finite = TRUE)
  (x - rng[1L]) / diff(rng)
}

variant_b = function(x) {
  lower = min(x, na.rm = TRUE)
  upper = max(x, na.rm = TRUE)
  (x - lower) / (upper - lower)
}

res = suppressMessages(bench::press(
  n = c(10L, 100L, 1000L, 10000L, 100000L),
  {
    x = rnorm(n)
    bench::mark(
      variant_a(x),
      variant_b(x)
    )
  }
))
res
#> # A tibble: 10 × 7
#>    expression        n      min   median `itr/sec` mem_alloc `gc/sec`
#>    <bch:expr>    <int> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#>  1 variant_a(x)     10    3.4µs    3.9µs   189430.        0B     37.9
#>  2 variant_b(x)     10 409.99ns 573.99ns  1321132.        0B      0  
#>  3 variant_a(x)    100   4.06µs   4.76µs   189461.    4.63KB     37.9
#>  4 variant_b(x)    100 696.98ns    820ns  1041067.      848B      0  
#>  5 variant_a(x)   1000   9.06µs  11.93µs    79220.    43.3KB     63.4
#>  6 variant_b(x)   1000   3.16µs    3.9µs   240959.    7.86KB     48.2
#>  7 variant_a(x)  10000  56.29µs  84.79µs    11643.  430.02KB     95.3
#>  8 variant_b(x)  10000  27.18µs  33.01µs    29087.   78.17KB     43.7
#>  9 variant_a(x) 100000 522.83µs 753.29µs     1322.     4.2MB    142. 
#> 10 variant_b(x) 100000 268.35µs 324.84µs     3061.   781.3KB     48.7

Created on 2024-06-19 with reprex v2.1.0