# Rescale a matrix between two limits

**URL:** <https://discourse.julialang.org/t/rescale-a-matrix-between-two-limits/99727>\
**Category:** General Usage\
**Created:** [June 1, 2023, 1:42pm UTC](https://discourse.julialang.org/t/rescale-a-matrix-between-two-limits/99727 "2023-06-01T13:42:04Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![RDuarte](https://avatars.discourse-cdn.com/v4/letter/r/a183cd/32.png) [@RDuarte](https://discourse.julialang.org/u/RDuarte)\
**Post date:** [June 1, 2023, 1:42pm UTC](https://discourse.julialang.org/t/rescale-a-matrix-between-two-limits/99727/1 "2023-06-01T13:42:04Z")

</div>

Dear all,

I’m learning Julia and I would like to rescale a matriz between [-1 and 1].  
In matlab I’m using rescale but i’m not sure it works in Julia.  
Do you have a clue of what can I use?

Thanks in advance.

---

<div class="post-metadata">

**Author:** ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)\
**Post date:** [June 1, 2023, 2:08pm UTC](https://discourse.julialang.org/t/rescale-a-matrix-between-two-limits/99727/2 "2023-06-01T14:08:26Z")

</div>

How do you want rescale it ? by rows ? by cols? overall ?

If overall:

```julia
julia> x = rand(3,4)
3×4 Matrix{Float64}:
 0.721988 0.849659 0.173933 0.277249
 0.946924 0.470537 0.686905 0.0554813
 0.113508 0.736393 0.378827 0.614165

julia> xl,xu = extrema(x)
(0.05548134618346434, 0.9469235535692043)

julia> xscaled = (x .- xl) .* (2 / (xu-xl)) .+ -1
3×4 Matrix{Float64}:
  0.495345 0.78178 -0.734247 -0.502453
  1.0 -0.0687999 0.416633 -1.0
 -0.869815 0.527663 -0.274557 0.253439

```

If by column either adapt the code above by col or use a package:

```julia
julia> using BetaML

julia> x = rand(3,4)
3×4 Matrix{Float64}:
 0.154214 0.229241 0.537544 0.639791
 0.595099 0.505548 0.231598 0.409011
 0.746998 0.637075 0.392721 0.270853

julia> xscaled = fit!(Scaler(MinMaxScaler(outputRange=(-1,1))),x)
3×4 Matrix{Float64}:
 -1.0 -1.0 1.0 1.0
  0.487506 0.354995 -1.0 -0.251052
  1.0 1.0 0.0532762 -1.0

```

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [June 1, 2023, 3:41pm UTC](https://discourse.julialang.org/t/rescale-a-matrix-between-two-limits/99727/3 "2023-06-01T15:41:58Z")

</div>

if `m,M = extrema(X)`

 ![scale m..M to -1..1](https://global.discourse-cdn.com/julialang/original/3X/a/f/af86934650067526885221760e4a12f5b790d87f.jpeg)

---

<div class="post-metadata">

**Author:** ![empet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/empet/32/221303_2.png) [@empet](https://discourse.julialang.org/u/empet)\
**Post date:** [June 1, 2023, 3:53pm UTC](https://discourse.julialang.org/t/rescale-a-matrix-between-two-limits/99727/4 "2023-06-01T15:53:42Z")

</div>

m, M extrema(A). This composition maps [m, M]\to[-1,1]:  
t\in[m, M]\to (t-m)/(M-m)\in[0,1]\to -1+2(t-m)/(M-m)\in[-1,1]

The first map is normalization. Hence the rescaled matrix is:

```julia
-1 .+ 2(A .-m)/(M-m)

```

More general, mapping an interval [a,b] onto [c,d] is realized by:  
f(t)=c+(d-c)(t-a)/(b-a)

---

<div class="post-metadata">

**Author:** ![RDuarte](https://avatars.discourse-cdn.com/v4/letter/r/a183cd/32.png) [@RDuarte](https://discourse.julialang.org/u/RDuarte)\
**Post date:** [June 1, 2023, 9:15pm UTC](https://discourse.julialang.org/t/rescale-a-matrix-between-two-limits/99727/5 "2023-06-01T21:15:15Z")

</div>

Hello Sylvaticus,

First of all, thank you for your help, but I’ve been testing your proposal and it gives me completely different results between Julia and Matlab.  
In matlab i’m doing:  
X = 1:5;  
R = rescale(X,-1,1) which gives me the following result:  
-1.0000 -0.5000 0 0.5000 1.0000

In Julia, with your proposal the result gives me the following result:  
(-1.0, -1.6, -2.2, -2.8, -3.4)

which is completely different.

What I need is a similar function than rescale function in matlab. In matlab this function scales the entries of `X`, lets say, the overal matrix to the interval [a,b], which in my case a and b are respectivelly -1 and 1.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [June 1, 2023, 9:56pm UTC](https://discourse.julialang.org/t/rescale-a-matrix-between-two-limits/99727/6 "2023-06-01T21:56:54Z")

</div>

> [@RDuarte](#):
>
> What I need is a similar function than rescale function in matlab

e.g.

```julia
function rescale(X, a, b)
    min, max = extrema(X)
    return @. (X - min) * ((b - a) * $(inv(max - min))) + a
end

```

which gives e.g.

```julia
julia> rescale(1:5, -1, 1)
-1.0:0.5:1.0

```

(Note that it will still work if `a` and/or `b` are arrays rather than scalars, e.g. to scale each row or column to a different minimum/maximum, similar to Matlab. I used `$(inv(max - min))` to hoist the `1/(max-min)` out of the broadcast loop, for efficiency, though maybe the compiler can do that?)

In actual practice, you’re likely to combine this kind of rescaling with other operations. ([Fusing loops is good](https://julialang.org/blog/2017/01/moredots/).) But in any case it’s a good learning exercise to figure out how to implement simple functions like `rescale` yourself. (Your own code can be just as fast as something “built in”, unlike Matlab.)

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [June 1, 2023, 10:23pm UTC](https://discourse.julialang.org/t/rescale-a-matrix-between-two-limits/99727/7 "2023-06-01T22:23:38Z")

</div>

> [@RDuarte](#):
>
> In Julia, with your proposal the result gives me the following result:  
> (-1.0, -1.6, -2.2, -2.8, -3.4)
> 
> which is completely different.

@sylvaticus’s answer seems correct to me:

```julia
julia> X = 1:5;

julia> xl,xu = extrema(X)
(1, 5)

julia> xscaled = (X .- xl) .* (2 / (xu-xl)) .+ -1
-1.0:0.5:1.0

```

---

<div class="post-metadata">

**Author:** ![RDuarte](https://avatars.discourse-cdn.com/v4/letter/r/a183cd/32.png) [@RDuarte](https://discourse.julialang.org/u/RDuarte)\
**Post date:** [June 1, 2023, 10:48pm UTC](https://discourse.julialang.org/t/rescale-a-matrix-between-two-limits/99727/8 "2023-06-01T22:48:19Z")

</div>

Thank you @stevengj . It works perfectly!

---

<div class="post-metadata">

**Author:** ![Dan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan/32/42581_2.png) [@Dan](https://discourse.julialang.org/u/Dan)\
**Post date:** [June 1, 2023, 11:37pm UTC](https://discourse.julialang.org/t/rescale-a-matrix-between-two-limits/99727/9 "2023-06-01T23:37:28Z")

</div>

In some cases, materializing another array is not needed. MappedArrays package allows doing the following:

```julia
using MappedArrays

function rescalemap(A,m = 0.0, M = 1.0)
    amin, amax = extrema(A)
    let k = inv(amax-amin)*(M-m)
        mappedarray(x-> k*(x-amin)+m, A)
    end
end

```

and then the following uses this function:

```julia
julia> A = rand(3,4)
3×4 Matrix{Float64}:
 0.288335 0.891559 0.244806 0.50186
 0.49325 0.54083 0.597688 0.739514
 0.278386 0.688678 0.14086 0.790771

julia> rescalemap(A, -1.0, 1.0)
3×4 mappedarray(var"#9#10"{Float64, Float64, Float64}...
 -0.607099 1.0 -0.72307 -0.0382319
 -0.0611698 0.065593 0.217073 0.594923
 -0.633607 0.459486 -1.0 0.73148

```

---

<div class="post-metadata">

**Author:** ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)\
**Post date:** [June 2, 2023, 8:06am UTC](https://discourse.julialang.org/t/rescale-a-matrix-between-two-limits/99727/10 "2023-06-02T08:06:33Z")

</div>

Hello, the method that I posted you should work:

```julia

julia> x = 1:5
1:5
julia> xl,xu = extrema(x)
(1, 5)
julia> xscaled = (x .- xl) .* (2 / (xu-xl)) .+ -1
-1.0:0.5:1.0

```

Note that when `x` is a range (like in your example), julia is able to keep the whole operation as a range, so the output remains a range. If you want to materialise it as as an array (most times you don’t need it) just call `collect` on it:

```julia
julia> xscaled_collected = collect(xscaled)
5-element Vector{Float64}:
 -1.0
 -0.5
  0.0
  0.5
  1.0

```

The interesting thing is that the trick of @stevengj somehow forces a collection of the array.  
For small arrays like in the example, the efficiency gain of keeping the `1/( max-min)` over the broadcasting loop prevails over the materialisation of the array, but for bigger arrays this is not the case:

```julia
julia> using BenchmarkTools

julia> @btime ($x .- minimum($x)) .* (2 / (maximum($x)-minimum($x))) .+ -1
  139.246 ns (0 allocations: 0 bytes)
-1.0:0.5:1.0

julia> function rescale(X, a, b)
           min, max = extrema(X)
           return @. (X - min) * ((b - a) * $(inv(max - min))) + a
       end
rescale (generic function with 1 method)

julia> @btime rescale($x,-1,1)
  38.231 ns (1 allocation: 96 bytes)
5-element Vector{Float64}:
 -1.0
 -0.5
  0.0
  0.5
  1.0

julia> x = 1:100000
1:100000

julia> @btime ($x .- minimum($x)) .* (2 / (maximum($x)-minimum($x))) .+ -1
  169.485 ns (0 allocations: 0 bytes)
-1.0:2.000020000200002e-5:1.0

julia> @btime rescale($x,-1,1)
  73.164 μs (2 allocations: 781.30 KiB)
100000-element Vector{Float64}:
 -1.0
 -0.999979999799998
 -0.999959999599996
 -0.999939999399994
 -0.999919999199992
 -0.99989999899999
 -0.999879998799988
 -0.999859998599986
 -0.999839998399984
 -0.999819998199982
  ⋮
  0.9998399983999839
  0.9998599985999859
  0.999879998799988
  0.9998999989999899
  0.9999199991999919
  0.999939999399994
  0.9999599995999959
  0.9999799997999981
  1.0

```
