In R, mean()
and median()
are standard functions which do what you\'d expect. mode()
tells you the internal storage mode of the objec
A small modification to Ken Williams' answer, adding optional params na.rm
and return_multiple
.
Unlike the answers relying on names()
, this answer maintains the data type of x
in the returned value(s).
stat_mode <- function(x, return_multiple = TRUE, na.rm = FALSE) {
if(na.rm){
x <- na.omit(x)
}
ux <- unique(x)
freq <- tabulate(match(x, ux))
mode_loc <- if(return_multiple) which(freq==max(freq)) else which.max(freq)
return(ux[mode_loc])
}
To show it works with the optional params and maintains data type:
foo <- c(2L, 2L, 3L, 4L, 4L, 5L, NA, NA)
bar <- c('mouse','mouse','dog','cat','cat','bird',NA,NA)
str(stat_mode(foo)) # int [1:3] 2 4 NA
str(stat_mode(bar)) # chr [1:3] "mouse" "cat" NA
str(stat_mode(bar, na.rm=T)) # chr [1:2] "mouse" "cat"
str(stat_mode(bar, return_mult=F, na.rm=T)) # chr "mouse"
Thanks to @Frank for simplification.
This builds on jprockbelly's answer, by adding a speed up for very short vectors. This is useful when applying mode to a data.frame or datatable with lots of small groups:
Mode <- function(x) {
if ( length(x) <= 2 ) return(x[1])
if ( anyNA(x) ) x = x[!is.na(x)]
ux <- unique(x)
ux[which.max(tabulate(match(x, ux)))]
}
It seems to me that if a collection has a mode, then its elements can be mapped one-to-one with the natural numbers. So, the problem of finding the mode reduces to producing such a mapping, finding the mode of the mapped values, then mapping back to some of the items in the collection. (Dealing with NA
occurs at the mapping phase).
I have a histogram
function that operates on a similar principal. (The special functions and operators used in the code presented herein should be defined in Shapiro and/or the neatOveRse. The portions of Shapiro and neatOveRse duplicated herein are so duplicated with permission; the duplicated snippets may be used under the terms of this site.) R pseudocode for histogram
is
.histogram <- function (i)
if (i %|% is.empty) integer() else
vapply2(i %|% max %|% seqN, `==` %<=% i %O% sum)
histogram <- function(i) i %|% rmna %|% .histogram
(The special binary operators accomplish piping, currying, and composition) I also have a maxloc
function, which is similar to which.max
, but returns all the absolute maxima of a vector. R pseudocode for maxloc
is
FUNloc <- function (FUN, x, na.rm=F)
which(x == list(identity, rmna)[[na.rm %|% index.b]](x) %|% FUN)
maxloc <- FUNloc %<=% max
minloc <- FUNloc %<=% min # I'M THROWING IN minloc TO EXPLAIN WHY I MADE FUNloc
Then
imode <- histogram %O% maxloc
and
x %|% map %|% imode %|% unmap
will compute the mode of any collection, provided appropriate map
-ping and unmap
-ping functions are defined.
Here are several ways you can do it in Theta(N) running time
from collections import defaultdict
def mode1(L):
counts = defaultdict(int)
for v in L:
counts[v] += 1
return max(counts,key=lambda x:counts[x])
def mode2(L):
vals = set(L)
return max(vals,key=lambda x: L.count(x))
def mode3(L):
return max(set(L), key=lambda x: L.count(x))
Adding in raster::modal()
as an option, although note that raster
is a hefty package and may not be worth installing if you don't do geospatial work.
The source code could be pulled out of https://github.com/rspatial/raster/blob/master/src/modal.cpp and https://github.com/rspatial/raster/blob/master/R/modal.R into a personal R package, for those who are particularly keen.
I found Ken Williams post above to be great, I added a few lines to account for NA values and made it a function for ease.
Mode <- function(x, na.rm = FALSE) {
if(na.rm){
x = x[!is.na(x)]
}
ux <- unique(x)
return(ux[which.max(tabulate(match(x, ux)))])
}