1

I have a data frame like this:

df <- data.frame(FC=c(1, 2, 4, 2, 1, -4, -2))

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

 FC
0.25
 0.5
   1
 0.5
0.25
  -1
-0.5

I have tried "scales" package in r

df$FC <- rescale(df$FC, to = c(0, 1))

But it is rescaling all values between 0-1.

How can I normalize columns by their individual range?

I really appreciate any help you can provide.

SUMIT
  • 563
  • 4
  • 12
  • 1
    Do you need the `range(df$FC)` – akrun Jun 16 '21 at 21:09
  • Sure if it can give the desired output. Thank you bro. – SUMIT Jun 16 '21 at 21:11
  • 1
    But, it is not giving your expected output though i.e. `rescale(df$FC, to = range(df$FC))` and `rescale(df$FC, to = range(abs(df$FC)))` – akrun Jun 16 '21 at 21:13
  • 1
    I thinnk the `from` is already doing the `range` and if we specify the `to` as also the range, it returns the input itself – akrun Jun 16 '21 at 21:17
  • I don't know much so I can not answer your question now. I need to check it how this rescale and range works. – SUMIT Jun 16 '21 at 21:18
  • 1
    Essentially running this on the positive and negative numbers separately https://stackoverflow.com/questions/5468280/scale-a-series-between-two-points – thelatemail Jun 16 '21 at 21:23
  • @thelatemail I will check and get back to you. Thanks for your kind help. – SUMIT Jun 16 '21 at 21:32

3 Answers3

3

Here is a base R option

transform(
    df,
    FC_scaled = FC / abs(ifelse(FC > 0, max(FC), min(FC)))
)

which gives

  FC FC_scaled
1  1      0.25
2  2      0.50
3  4      1.00
4  2      0.50
5  1      0.25
6 -4     -1.00
7 -2     -0.50
ThomasIsCoding
  • 96,636
  • 9
  • 24
  • 81
  • 1
    oh wow much needed, it is working as required. Thank your kind help. Have a good day. – SUMIT Jun 16 '21 at 21:35
2

You could just slice your data into positives and negatives and handle each individually.

df <- data.frame(FC=c(1, 2, 4, 2, 1, -4, -2))

library(scales)

df[which(df$FC>0),] <- rescale(df[which(df$FC>0),], to=c(.25,1))
df[which(df$FC<0),] <- rescale(df[which(df$FC<0),], to=c(-.5,-1))

df

Output:

     FC
1  0.25
2  0.50
3  1.00
4  0.50
5  0.25
6 -0.50
7 -1.00

Please note however, that I did not specify the range to be between 0 and 1 because that would not get you the output you were looking for. If I did the output would be this:

          FC
1  0.0000000
2  0.3333333
3  1.0000000
4  0.3333333
5  0.0000000
6  0.0000000
7 -1.0000000

Dharman
  • 30,962
  • 25
  • 85
  • 135
Marshall K
  • 302
  • 1
  • 8
2

We may also use sign with similar logic as in @ThomasIsCoding post

df$FC_scaled <- with(df, FC/setNames(range(FC),
           c(-1, 1))[as.character(sign(FC))] * sign(FC))

-output

 df
  FC FC_scaled
1  1      0.25
2  2      0.50
3  4      1.00
4  2      0.50
5  1      0.25
6 -4     -1.00
7 -2     -0.50
akrun
  • 874,273
  • 37
  • 540
  • 662