Search code examples
rtidyversescalerescale

Rescale positive and negative numbers into [0, 1] and [-1, 0]


I have a data frame like this:

Input_df <- data.frame(Enl_ID = c("INTS121410", "INTS175899", "INTS171428", "INTS156006", "INTS196136", "INTS114771" ), `CN4244` = c(5, 0, -0.4, -0.6, 10, 2), `CN4249` = c(10, -4, -10, -2, 6, 0), `CN4250` = c(40, 10, 4, -10, 0, 4))

I'm trying to rescale the positive values between 0-1 and negative values between 0 to -1 so the output would be like

Output_df <- data.frame(Enl_ID = c("INTS121410", "INTS175899", "INTS171428", "INTS156006", "INTS196136", "INTS114771" ), `CN4244` = c(0.5, 0, -0.66, -1, 1, 0.2), `CN4249` = c(1, -0.4, -1, -0.2, 0.6, 0), `CN4250` = c(1, 0.25, 0.1, -1, 0, 0.1))

I found few examples like at stackoverflow but this is only for single-column and my file run into almost 2000 column so it is not possible to do it manually on every column.

Any idea how to do it?

Any help would be appreciated. Thanks in advance


Solution

  • You could use

    library(dplyr)
    
    Input_df %>% 
      mutate(across(starts_with("CN"), ~.x / max(abs(.x))))
    

    This returns

          Enl_ID CN4244 CN4249 CN4250
    1 INTS121410   0.50    1.0   1.00
    2 INTS175899   0.00   -0.4   0.25
    3 INTS171428  -0.04   -1.0   0.10
    4 INTS156006  -0.06   -0.2  -0.25
    5 INTS196136   1.00    0.6   0.00
    6 INTS114771   0.20    0.0   0.10
    

    Or, if you want different rescaling factors for positive and negative values:

    Input_df %>% 
      mutate(across(starts_with("CN"), 
                    ~case_when(.x >= 0 ~ .x / max(.x), 
                               TRUE ~ - .x / min(.x))))
    

    This returns

          Enl_ID     CN4244 CN4249 CN4250
    1 INTS121410  0.5000000    1.0   1.00
    2 INTS175899  0.0000000   -0.4   0.25
    3 INTS171428 -0.6666667   -1.0   0.10
    4 INTS156006 -1.0000000   -0.2  -1.00
    5 INTS196136  1.0000000    0.6   0.00
    6 INTS114771  0.2000000    0.0   0.10