Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return name of column containing max value, from only certain selected columns in a data.frame

Tags:

dataframe

r

I would like to obtain (in an new column in the data.table) the column name of the column that contains the maximum value in only a few columns in a data.frame.

Here is an example data.frame

# creating the vectors then the data frame ------
id = c("a", "b", "c", "d")
 ignore = c(1000,1000, 1000, 1000) 
 s1 = c(0,0,0,100)
s2 = c(100,0,0,0)
s3 = c(0,0,50,0)
s4 = c(50,0,50,0)
 df1 <- data.frame(id,ignore,s1,s2,s3,s4)  

(1) now I want to find the column name of the maximum number in each row, from the columns s1-s4. (i.e. ignore the column called "ignore")

(2) If there is a tie for the maximum, I would like the last (e.g. s4) column name returned.

(3) as an extra favour - if all are 0, I would ideally like NA returned

here is my best attempt so far

df2 <- cbind(df1,do.call(rbind,apply(df1,1,function(x) {data.frame(max.col.name=names(df1)[which.max(x)],stringsAsFactors=FALSE)})))

this returns ignore in each case, and (except for row b) works if I remove this column, and reorder the s1-s4 columns as s4-s1.

How would you approach this?

Many thanks indeed.

like image 927
threeisles Avatar asked Oct 30 '22 19:10

threeisles


2 Answers

We use grep to create a column index for columns that start with 's' followed by numbers ('i1'). To get the row index of the subset dataset ('df1[i1]') that has the maximum value, we can use max.col with the option ties.method='last'. To convert the rows that have only 0 values to NA, we get the rowSums, check if that is 0 (==0) and convert those to NA (NA^) and multiply with max.col output. This can be used to extract the column names of subset dataset.

i1 <- grep('^s\\d+', names(df1))
names(df1)[i1][max.col(df1[i1], 'last')*NA^(rowSums(df1[i1])==0)]
#[1] "s2" NA   "s4" "s1"
like image 154
akrun Avatar answered Nov 09 '22 15:11

akrun


library(dplyr)
library(tidyr)

df1 = data_frame(
  id = c("a", "b", "c", "d")
  ignore = c(1000,1000, 1000, 1000) 
  s1 = c(0,0,0,100)
  s2 = c(100,0,0,0)
  s3 = c(0,0,50,0)
  s4 = c(50,0,50,0))

result = 
  df1 %>%
  gather(variable, value, -id, -ignore) %>%
  group_by(id) %>%
  slice(value %>%
          {. == max(.)} %>%
          which %>%
          last) %>%
  ungroup %>%
  mutate(variable_fix = ifelse(value == 0,
                               NA,
                               variable))
like image 31
bramtayl Avatar answered Nov 09 '22 16:11

bramtayl