How isolate just the smallest magnitude values from an R data frame

74 views Asked by At

My Problem

I have the following (simplified) dataframe df :

        A    B    C
[1,]    2   -5   20
[2,]  -10   -1   10
[3,]   10  -10    0 

I want to isolate just the values of the smallest magnitude:

[ 2, -1, 0 ]

How would I do that?

What I've Tried

So far I've just got it to show me what the minimum absolute value is per row:

  MagMin <- vector()
  
  for(i in 1:nrow(df)){ 
    sub <- df[i,]
    MagMin[i] <- min(abs(df[i,]))
    }

Which gives me [2, 1, 0], but obviously, I've lost the signage for what way the smallest value goes.

I found a nice answer to the question in python, but I can't think how to apply it here!

1

There are 1 answers

0
r2evans On BEST ANSWER
apply(mat, 1, function(z) z[which.min(abs(z))])
# [1,] [2,] [3,] 
#    2   -1    0 

Walk-through:

  • When you want the min-magnitude, min(abs(val)) will return the positive of that, which you know ...

    val <- c(-10L, -1L, 10L)
    min(abs(val))
    # [1] 1
    
  • We can use which.min(abs(val)) to determine which in the vector is the min-magnitude, which returns an index on the vector:

    which.min(abs(val))
    # [1] 2
    
  • Using that, we can extract the specific value (pos or neg) based on the min-magnitude:

    val[which.min(abs(val))]
    # [1] -1
    
  • to repeat the operation for each row, we use apply(mat, 1, ...). The 1 is for MARGIN=1 which means "by row", and the third argument (FUN=) is a function that takes exactly one argument and does something with it; in this case, the first time it's called, z is effectively mat[1,], with the values c(2, -5, 20); the second time, it's effectively mat[2,] with values c(-10, -1, 10); etc.


Data

mat <- structure(list(A = c(2L, -10L, 10L), B = c(-5L, -1L, -10L), C = c(20L, 10L, 0L)), class = "data.frame", row.names = c("[1,]", "[2,]", "[3,]"))