'Scale a series between two points

How do I scale a series such that the first number in the series is 0 and last number is 1. I looked into 'approx', 'scale' but they do not achieve this objective.

# generate series from exponential distr
s = sort(rexp(100))

# scale/interpolate 's' such that it starts at 0 and ends at 1?
# approx(s)
# scale(s)


Solution 1:[1]

The scales package has a function that will do this for you: rescale.

library("scales")
rescale(s)

By default, this scales the given range of s onto 0 to 1, but either or both of those can be adjusted. For example, if you wanted it scaled from 0 to 10,

rescale(s, to=c(0,10))

or if you wanted the largest value of s scaled to 1, but 0 (instead of the smallest value of s) scaled to 0, you could use

rescale(s, from=c(0, max(s)))

Solution 2:[2]

Alternatively:

scale(x,center=min(x),scale=diff(range(x)))

(untested)

This has the feature that it attaches the original centering and scaling factors to the output as attributes, so they can be retrieved and used to un-scale the data later (if desired). It has the oddity that it always returns the result as a (columnwise) matrix, even if it was passed a vector; you can use drop(scale(...)) if you want a vector instead of a matrix (this usually doesn't matter but the matrix format can occasionally cause trouble downstream ... in my experience more often with tibbles/in tidyverse, although I haven't stopped to examine exactly what's going wrong in these cases).

Solution 3:[3]

This should do it:

reshape::rescaler.default(s, type = "range")

EDIT

I was curious about the performance of the two methods

> system.time(replicate(100, range01(s)))
   user  system elapsed 
   0.56    0.12    0.69 
> system.time(replicate(100, reshape::rescaler.default(s, type = "range")))
   user  system elapsed 
   0.53    0.18    0.70 

Extracting the raw code from reshape::rescaler.default

range02 <- function(x) {
    (x - min(x, na.rm=TRUE)) / diff(range(x, na.rm=TRUE))
    }

> system.time(replicate(100, range02(s)))
   user  system elapsed 
   0.56    0.12    0.68 

Yields similar result.

Solution 4:[4]

You can also make use of the caret package which will provide you the preProcess function which is just simple like this:

preProcValues <- preProcess(yourData, method = "range")
dataScaled <- predict(preProcValues, yourData)

More details on the package help.

Solution 5:[5]

I created following function in r:

ReScale <- function(x,first,last){(last-first)/(max(x)-min(x))*(x-min(x))+first}

Here, first is start point, last is end point.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Brian Diggs
Solution 2
Solution 3
Solution 4 brunoazev
Solution 5 Satpal Singh