Spartacus Rocha
Spartacus Rocha

Reputation: 606

R calculate mode for a row, not a column

Usually people want to calculate mode from each question, but in my case I need to calculate the mode for each respondente, across all questions.

This is how my data looks like:

> head(TiposMotivA)
  Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 Q10 Q11 Q12 Q13 Q14 Q15 Q16 Q17 Q18 Q19 Q20 Q21
1  5  4  4  4  6  6  7  6  4   6   6   6   4   4   4   4   6   7   4   4   6
2  5  4  4  5  5  5  5  5  5   5   7   5   4   3   1   6   6   5   6   7   7
3  4  5  4  4  5  4  5  4  5   4   5   4   5   4   5   4   5   4   5   4   5
4  5  5  7  7  4  6  6  6  7   7   6   7   7   6   6   7   4   7   6   6   7
5  6  1  7  6  7  7  7  7  7   7   6   7   2   2   3   6   3   7   7   7   7
6  4  4  3  3  4  5  4  3  4   7   6   6   4   4   6   4   5   7   6   6   7

This Solution was the best I found so far:

apply(TiposMotivA, 1, Compose(table,
                    function(i) i==max(i),
                    which,
                    names,
                    function(i) paste0(i, collapse='/')
                    )
      )

It was provided by Matthew Lundberg here: Select majority number of each row in matrix using r

It produced this:

 [1] "4"   "5"   "4"   "7"   "7"   "4"   "7"   "6"   "7"   "7"   "7"   "7"   "7" 
[14] "5/6" "7"   "6"   "7"   "6"   "7"   "7"   "7"   "7"   "7"   "7"   "7"   "7"
[27] "7"   "7"   "7"   "5"   "2"   "7"   "7"   "7"   "7"   "7"   "6"   "6"   "7"
[40] "4/7" "3"   "4"   "7"   "5/7" "6"   "7"   "7"   "6"   "7"   "6"   "7"   "7"
[53] "7"   "6"   "7"   "7"   "5/7" "7"   "7"   "7"   "7"   "7"  
> 

My problem, which might seem basic for some, is driving me nuts. I need only one mode per row, so when there are two, I need simply the first. I have tried to use split() without success.

So, what I need is to get mode for each row, as presented above, but having only the first mode when there are two.

Something like this:

 [1] "4"   "5"   "4"   "7"   "7"   "4"   "7"   "6"   "7"   "7"   "7"   "7"   "7" 
[14] "5" "7"   "6"   "7"   "6"   "7"   "7"   "7"   "7"   "7"   "7"   "7"   "7"
[27] "7"   "7"   "7"   "5"   "2"   "7"   "7"   "7"   "7"   "7"   "6"   "6"   "7"
[40] "4" "3"   "4"   "7"   "5" "6"   "7"   "7"   "6"   "7"   "6"   "7"   "7"
[53] "7"   "6"   "7"   "7"   "5" "7"   "7"   "7"   "7"   "7"  
> 

Any help is gonna be pretty appreciated.

Upvotes: 2

Views: 2734

Answers (3)

G. Grothendieck
G. Grothendieck

Reputation: 269371

which.max can be used to find the position of the first maximum:

apply(TiposMotivA, 1, function(x) { tab <- table(x); names(tab)[which.max(tab)] } )

giving:

  1   2   3   4   5   6 
"4" "5" "4" "7" "7" "4" 

No packages are needed.

Upvotes: 4

akrun
akrun

Reputation: 886938

Another option would be to change from "wide" to "long" format using melt, convert the "data.frame" to "data.table" with setDT, get the count (.N), grouped by variables ("Var1", "value"), find the index of maximum value of "N" (which.max(N)) and use that to get the "value", grouped by "Var1"

library(reshape2)
library(data.table)
setDT(melt(as.matrix(TiposMotivA)))[, .N ,.(Var1, value)][,
                             value[which.max(N)], Var1]$V1
#[1] 4 5 4 7 7 4

Or you could use base R functions (modified from the link)

apply(TiposMotivA, 1, function(idx) which.max(tabulate(idx)))
#1 2 3 4 5 6 
#4 5 4 7 7 4 

Upvotes: 2

tkmckenzie
tkmckenzie

Reputation: 1363

The solution you found will paste together all of the modes, we can modify it a little bit to just give you the first mode:

apply(TiposMotivA, 1, Compose(table,
                    function(i) i==max(i),
                    which,
                    names,
                    function(i) i[1]
                    )
      )

Upvotes: 2

Related Questions