2
votes

I have a data frame that looks like this:

ID    val1    val2    val3
A07   -0.01   -0.03   0.01
A08   0.05    -0.07   0.02
B01   0.02    0.03    -0.01

For each row, I'd like to identify the largest absolute value in columns val1, val2, and val3. I'd then like to print the signed value (e.g. the originally formatted integer) of the largest absolute value to a new column. The result would look like this:

ID    val1    val2    val3    val.new
A07   -0.01   -0.03   0.01    -0.03
A08   0.05    -0.07   0.02    -0.07
B01   0.04    0.02    -0.01   0.04

I am currently using apply to identify the maximum absolute value in each row across the desired columns and print to a new column, like this:

df[,"val.new"] = apply(abs(df[,2:4]), 1, max)

But this of course returns the max absolute value, without the sign:

ID    val1    val2    val3    val.new
A07   -0.01   -0.03   0.01    0.03
A08   0.05    -0.07   0.02    0.07
B01   0.04    0.02    -0.01   0.04

I can't figure out how to return the signed value that was used to identify the max. How do I fix that?

Thanks!

2
Thanks @e.matt! I've tried that out and I end up with the same issue...the absolute value is printed to the new column rather than the signed value.nrcombs
@nrcombs there is a discrepancy in your example - you have the 3rd value of val1 as 0.02 in the first data frame but 0.04 in the others, which affects the result.Allan Cameron

2 Answers

2
votes

You can do:

df$val.new <- apply(df[-1], 1, function(x) x[which.max(abs(x))])

df
#>    ID  val1  val2  val3 val.new
#> 1 A07 -0.01 -0.03  0.01   -0.03
#> 2 A08  0.05 -0.07  0.02   -0.07
#> 3 B01  0.02  0.03 -0.01    0.03

Data used

df <- structure(list(ID = structure(1:3, .Label = c("A07", "A08", "B01"
), class = "factor"), val1 = c(-0.01, 0.05, 0.02), val2 = c(-0.03, 
-0.07, 0.03), val3 = c(0.01, 0.02, -0.01)), row.names = c(NA, 
-3L), class = "data.frame")

df
#>    ID  val1  val2  val3
#> 1 A07 -0.01 -0.03  0.01
#> 2 A08  0.05 -0.07  0.02
#> 3 B01  0.02  0.03 -0.01
0
votes

We can use vectorized row/column index in base R

df$val.new <-  df[-1][cbind(seq_len(nrow(df)), max.col(abs(df[-1]), 'first'))]

-output

df
#   ID  val1  val2  val3 val.new
#1 A07 -0.01 -0.03  0.01   -0.03
#2 A08  0.05 -0.07  0.02   -0.07
#3 B01  0.02  0.03 -0.01    0.03

data

df <- structure(list(ID = structure(1:3, .Label = c("A07", "A08", "B01"
), class = "factor"), val1 = c(-0.01, 0.05, 0.02), val2 = c(-0.03, 
-0.07, 0.03), val3 = c(0.01, 0.02, -0.01)), row.names = c(NA, 
-3L), class = "data.frame")