Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find all tied maximum values in a row and return true or false if column contains max value

Tags:

r

I have some data containing numeric columns :

df <- data.frame(v1 = c(0,1,2,3,4,5,6,7,8,9),
                 v2 = c(2,1,4,7,6,7,8,9,0,1),
                 v3 = c(4,1,6,7,8,9,0,1,2,3),
                 v4 = c(0,1,2,7,4,5,6,7,8,9),
                 v5 = c(0,1,6,3,6,9,8,9,0,1))

I can find the first maximum value and return its column name using which.max:

df$max <- colnames(df)[apply(df,1,which.max)]

Instead I would like to add five new columns and insert TRUE if the corresponding column is the max value or tied for the max value, and FALSE if not:

   v1 v2 v3 v4 v5 v1max v2max v3max v4max v5max
1   0  2  4  0  0 FALSE FALSE TRUE  FALSE FALSE
2   1  1  1  1  1 TRUE  TRUE  TRUE  TRUE  TRUE  
3   2  4  6  2  6 FALSE FALSE TRUE  FALSE TRUE     
4   3  7  7  7  3 FALSE TRUE  TRUE  TRUE  FALSE
5   4  6  8  4  6 FALSE FALSE TRUE  FALSE FALSE
6   5  7  9  5  9 FALSE FALSE TRUE  FALSE TRUE
7   6  8  0  6  8 FALSE TRUE  FALSE FALSE TRUE
8   7  9  1  7  9 FALSE TRUE  FALSE FALSE TRUE
9   8  0  2  8  0 TRUE  FALSE FALSE TRUE  FALSE
10  9  1  3  9  1 TRUE  FALSE FALSE TRUE  FALSE

Is there a simple way to achieve this?

like image 491
nogbad Avatar asked Sep 12 '25 20:09

nogbad


1 Answers

A simple and efficient solution would be to get row-wise maximum using do.call and pmax and compare it with the dataframe to get logical vectors which can be assigned as new columns.

df[paste0(names(df), "max")] <- df == do.call(pmax, df)

df
#   v1 v2 v3 v4 v5 v1max v2max v3max v4max v5max
#1   0  2  4  0  0 FALSE FALSE  TRUE FALSE FALSE
#2   1  1  1  1  1  TRUE  TRUE  TRUE  TRUE  TRUE
#3   2  4  6  2  6 FALSE FALSE  TRUE FALSE  TRUE
#4   3  7  7  7  3 FALSE  TRUE  TRUE  TRUE FALSE
#5   4  6  8  4  6 FALSE FALSE  TRUE FALSE FALSE
#6   5  7  9  5  9 FALSE FALSE  TRUE FALSE  TRUE
#7   6  8  0  6  8 FALSE  TRUE FALSE FALSE  TRUE
#8   7  9  1  7  9 FALSE  TRUE FALSE FALSE  TRUE
#9   8  0  2  8  0  TRUE FALSE FALSE  TRUE FALSE
#10  9  1  3  9  1  TRUE FALSE FALSE  TRUE FALSE

A solution with apply could be

df[paste0(names(df), "max")] <- t(apply(df, 1, function(x) x == max(x)))
like image 101
Ronak Shah Avatar answered Sep 14 '25 12:09

Ronak Shah