Denormalize data with Caret in R

Viewed 92

I can easily normalize and denormalize data with RSNNS packages.

You can see example below

library(RSNNS)
           
               data(iris)
               values <- normalizeData(iris[,1:4])
    
     summary(values)
    
        V1                 V2                V3                V4         
     Min.   :-1.86378   Min.   :-2.4258   Min.   :-1.5623   Min.   :-1.4422  
     1st Qu.:-0.89767   1st Qu.:-0.5904   1st Qu.:-1.2225   1st Qu.:-1.1799  
     Median :-0.05233   Median :-0.1315   Median : 0.3354   Median : 0.1321  
     Mean   : 0.00000   Mean   : 0.0000   Mean   : 0.0000   Mean   : 0.0000  
     3rd Qu.: 0.67225   3rd Qu.: 0.5567   3rd Qu.: 0.7602   3rd Qu.: 0.7880  
     Max.   : 2.48370   Max.   : 3.0805   Max.   : 1.7799   Max.   : 1.7064 
    
denormalizeData(values, getNormParameters(values))
 

Now I want to do same thing but with min-max scaling (with values between 0 and 1).

        library(caret)   
           preproc2 <- preProcess(iris[,1:4], method=c("range"))
           values <- predict(preproc2, iris[,1:4])
           summary(values)

Sepal.Length     Sepal.Width      Petal.Length     Petal.Width     
 Min.   :0.0000   Min.   :0.0000   Min.   :0.0000   Min.   :0.00000  
 1st Qu.:0.2222   1st Qu.:0.3333   1st Qu.:0.1017   1st Qu.:0.08333  
 Median :0.4167   Median :0.4167   Median :0.5678   Median :0.50000  
 Mean   :0.4287   Mean   :0.4406   Mean   :0.4675   Mean   :0.45806  
 3rd Qu.:0.5833   3rd Qu.:0.5417   3rd Qu.:0.6949   3rd Qu.:0.70833  
 Max.   :1.0000   Max.   :1.0000   Max.   :1.0000   Max.   :1.00000  

So can anybody help me how denormalize with Caret package ?

1 Answers

This still isn't as simple as many of the methods that Python has, but it works. I know I have needed to return the data to its original state on many occasions. Either way, the option is nice to have.

I made some simple data, so you may see how this works easier.

ttx <- matrix(data = c(1:10, 0:9, 
                       seq(10, 100, by = 10)), 
              nrow = 10, ncol = 3) %>% as.data.frame()

names(ttx) = c("x", "y", "z")
ttx
#     x y   z
# 1   1 0  10
# 2   2 1  20
# 3   3 2  30
# 4   4 3  40
# 5   5 4  50
# 6   6 5  60
# 7   7 6  70
# 8   8 7  80
# 9   9 8  90
# 10 10 9 100 

Then I used the preProcess function from caret, just as you used it.

# show what preprocess makes
ppo <- preProcess(ttx, method = c("range"))
predict(ppo, ttx)
#            x         y         z
# 1  0.0000000 0.0000000 0.0000000
# 2  0.1111111 0.1111111 0.1111111
# 3  0.2222222 0.2222222 0.2222222
# 4  0.3333333 0.3333333 0.3333333
# 5  0.4444444 0.4444444 0.4444444
# 6  0.5555556 0.5555556 0.5555556
# 7  0.6666667 0.6666667 0.6666667
# 8  0.7777778 0.7777778 0.7777778
# 9  0.8888889 0.8888889 0.8888889
# 10 1.0000000 1.0000000 1.0000000 

You could do this manually, like this:

# the formula used is
scaler <- function(vx){ 
  vals <- (vx - min(vx))/(max(vx) - min(vx))
  return(vals)
}

scTtx <- scaler(ttx$x)
#  [1] 0.0000000 0.1111111 0.2222222 0.3333333 0.4444444 0.5555556 0.6666667
#  [8] 0.7777778 0.8888889 1.0000000 

To revert the data back, you just need the inverse.

# where xv is the data column, mx is the max or the original data
# nx is the minimum of the original data
descaler <- function(xv, mx, nx){ 
  dvals <- xv * (mx - nx) + nx
  dvals <- round(dvals, digits = 5)
  return(dvals)
}

dscttx <- descaler(scTtx, max(ttx$x), min(ttx$x))
dscttx
#  [1]  1  2  3  4  5  6  7  8  9 10 

However, you can use the preProcess function from caret, because that object includes the ranges. That's how you are able to keep applying it (predicting it?).

I wrote this function to show you what I mean.

# preProcess saved the range data, so you can use preProcess to descale
# this is written assuming you're using a data.frame with multiple columns
descaler2 <- function(xv, ppo){
  lxv <- length(xv)
  vx <- sapply(1:lxv, function(x) {
    descaler(xv[, x], ppo$ranges[2, x], ppo$ranges[1, x])
  })
  vx <- data.frame(vx)
  names(vx) <- names(xv)
  return(vx)
}

Here I'm going to use the scaled data and the object created from preProcess.

tellMe <- descaler2(predict(ppo, ttx), ppo) # should return ttx
tellMe
#     x y   z
# 1   1 0  10
# 2   2 1  20
# 3   3 2  30
# 4   4 3  40
# 5   5 4  50
# 6   6 5  60
# 7   7 6  70
# 8   8 7  80
# 9   9 8  90
# 10 10 9 100 

If you wanted to apply this to your data, just keep the descaler and descaler2 functions to return the data to its original state. Just keep in mind this is specific to range. You will only need to use descaler2 but that function calls the other one.

Related