Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find row-wise minimum and return value and its corresponding column name

Tags:

r

Consider the following matrix m:

    ca bsa rd zaa
ada  3   4  3   2
aca  1   4  5   2
ara  3   4  3   2
ava  3   4  5   2

I'm trying to find, for each row, the minimum value and return a data.frame in the form of:

    q   s d
1 ada zaa 2
2 aca  ca 1
3 ara zaa 2
4 ava zaa 2

Right now I'm doing:

res <- t(sapply(seq(nrow(m)), function(i) {
  j <- which.min(m[i,])
  c(q = rownames(m)[i],
    s = colnames(m)[j],
    d = m[i,j])}))

res <- data.frame(res)
res$d <- as.numeric(res$d)

I'm looking for a better way to build this.

It feels rather inefficient to build res using c() (coercing all the components to the same type) then convert it to a data.frame and finally change d to numeric in order to obtain the following structure:

'data.frame':   4 obs. of  3 variables:
 $ q: Factor w/ 4 levels "aca","ada","ara",..: 2 1 3 4
 $ s: Factor w/ 2 levels "ca","zaa": 2 1 2 2
 $ d: num  2 1 2 2 

I would also need to handle a case where there could be multiple minima


Data

m <- structure(c(3, 1, 3, 3, 4, 4, 4, 4, 3, 5, 3, 5, 2, 2, 2, 2), .Dim = c(4L, 
4L), .Dimnames = list(c("ada", "aca", "ara", "ava"), c("ca", "bsa", "rd", "zaa")))
like image 413
Steven Beaupré Avatar asked Dec 19 '22 01:12

Steven Beaupré


1 Answers

You may find the column index of the minimum value for each row by using max.col on the negated version of the matrix.

col_id <- max.col(-m)
data.frame(q = rownames(m), s = colnames(m)[col_id],
           d = m[cbind(1:length(col_id), col_id)])
#     q   s d
# 1 ada zaa 2
# 2 aca  ca 1
# 3 ara zaa 2
# 4 ava zaa 2
like image 115
Henrik Avatar answered Jan 31 '23 00:01

Henrik