Search code examples
rarraysdataframesubsetmagnitude

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


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!


Solution

  • 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,]"))