Есть ли встроенная функция для нахождения режима? - PullRequest
356 голосов
/ 30 марта 2010

В R * mean() и median() - это стандартные функции, которые выполняют то, что вы ожидаете. mode() сообщает вам режим внутреннего хранения объекта, а не значение, которое встречается чаще всего в его аргументе. Но есть ли стандартная библиотечная функция, которая реализует статистический режим для вектора (или списка)?

Ответы [ 30 ]

363 голосов
/ 19 ноября 2011

Еще одно решение, которое работает как для числовых, так и для символьных / факторных данных:

Mode <- function(x) {
  ux <- unique(x)
  ux[which.max(tabulate(match(x, ux)))]
}

На моей маленькой машинке, которая может генерировать и находить режим 10-целочисленного вектора примерно за полсекунды.

Если в вашем наборе данных может быть несколько режимов, вышеуказанное решение использует тот же подход, что и which.max, и возвращает значение первого набора набора режимов. Чтобы вернуть все режимы, используйте этот вариант (из @digEmAll в комментариях):

Modes <- function(x) {
  ux <- unique(x)
  tab <- tabulate(match(x, ux))
  ux[tab == max(tab)]
}
63 голосов
/ 30 марта 2010

Существует пакет modeest, который предоставляет оценки режима одномерных одномодальных (и иногда мультимодальных) данных и значений режимов обычных распределений вероятностей.

mySamples <- c(19, 4, 5, 7, 29, 19, 29, 13, 25, 19)

library(modeest)
mlv(mySamples, method = "mfv")

Mode (most likely value): 19 
Bickel's modal skewness: -0.1 
Call: mlv.default(x = mySamples, method = "mfv")

Для получения дополнительной информации см. эту страницу

55 голосов
/ 30 марта 2010

нашел это в списке рассылки r, надеюсь, это поможет. Это также то, о чем я думал в любом случае. Вы хотите, чтобы таблица () данных, сортировать, а затем выбрать имя. Это взломано, но должно работать.

names(sort(-table(x)))[1]
44 голосов
/ 03 сентября 2014

Мне показалось, что пост Кена Уильямса выше, я добавил несколько строк для учета значений NA и сделал его функцией для удобства.

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)))])
}
28 голосов
/ 14 декабря 2012

Быстрый и грязный способ оценки режима вектора чисел, который, по вашему мнению, исходит из непрерывного одномерного распределения (например, нормального распределения), определяет и использует следующую функцию:

estimate_mode <- function(x) {
  d <- density(x)
  d$x[which.max(d$y)]
}

Затем, чтобы получить оценку режима:

x <- c(5.8, 5.6, 6.2, 4.1, 4.9, 2.4, 3.9, 1.8, 5.7, 3.2)
estimate_mode(x)
## 5.439788
14 голосов
/ 25 марта 2013

Следующая функция имеет три вида:

method = "mode" [по умолчанию]: вычисляет режим для унимодального вектора, иначе возвращает NA
method = "nmodes": вычисляет количество мод в векторе
method = "mode": перечисляет все моды для унимодального или полимодального вектора

modeav <- function (x, method = "mode", na.rm = FALSE)
{
  x <- unlist(x)
  if (na.rm)
    x <- x[!is.na(x)]
  u <- unique(x)
  n <- length(u)
  #get frequencies of each of the unique values in the vector
  frequencies <- rep(0, n)
  for (i in seq_len(n)) {
    if (is.na(u[i])) {
      frequencies[i] <- sum(is.na(x))
    }
    else {
      frequencies[i] <- sum(x == u[i], na.rm = TRUE)
    }
  }
  #mode if a unimodal vector, else NA
  if (method == "mode" | is.na(method) | method == "")
  {return(ifelse(length(frequencies[frequencies==max(frequencies)])>1,NA,u[which.max(frequencies)]))}
  #number of modes
  if(method == "nmode" | method == "nmodes")
  {return(length(frequencies[frequencies==max(frequencies)]))}
  #list of all modes
  if (method == "modes" | method == "modevalues")
  {return(u[which(frequencies==max(frequencies), arr.ind = FALSE, useNames = FALSE)])}  
  #error trap the method
  warning("Warning: method not recognised.  Valid methods are 'mode' [default], 'nmodes' and 'modes'")
  return()
}
10 голосов
/ 31 марта 2010

Вот другое решение:

freq <- tapply(mySamples,mySamples,length)
#or freq <- table(mySamples)
as.numeric(names(freq)[which.max(freq)])
9 голосов
/ 12 сентября 2013

Я пока не могу голосовать, но ответ Расмуса Батха - это то, что я искал. Тем не менее, я бы немного его изменил, позволяя ограничить распределение, например, для значений только между 0 и 1.

estimate_mode <- function(x,from=min(x), to=max(x)) {
  d <- density(x, from=from, to=to)
  d$x[which.max(d$y)]
}

Мы знаем, что вы можете вообще не хотеть ограничивать свой дистрибутив, поэтому установите из = - "БОЛЬШОЙ НОМЕР" в = "БОЛЬШОЙ НОМЕР"

8 голосов
/ 20 июля 2017

Небольшая модификация ответа Кена Уильямса, добавление необязательных параметров na.rm и return_multiple.

В отличие от ответов, основанных на names(), этот ответ поддерживает тип данных x в возвращаемых значениях.

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])
}

Чтобы показать, что он работает с необязательными параметрами и поддерживает тип данных:

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"

Спасибо @Frank за упрощение.

7 голосов
/ 18 ноября 2011

Я написал следующий код для генерации режима.

MODE <- function(dataframe){
    DF <- as.data.frame(dataframe)

    MODE2 <- function(x){      
        if (is.numeric(x) == FALSE){
            df <- as.data.frame(table(x))  
            df <- df[order(df$Freq), ]         
            m <- max(df$Freq)        
            MODE1 <- as.vector(as.character(subset(df, Freq == m)[, 1]))

            if (sum(df$Freq)/length(df$Freq)==1){
                warning("No Mode: Frequency of all values is 1", call. = FALSE)
            }else{
                return(MODE1)
            }

        }else{ 
            df <- as.data.frame(table(x))  
            df <- df[order(df$Freq), ]         
            m <- max(df$Freq)        
            MODE1 <- as.vector(as.numeric(as.character(subset(df, Freq == m)[, 1])))

            if (sum(df$Freq)/length(df$Freq)==1){
                warning("No Mode: Frequency of all values is 1", call. = FALSE)
            }else{
                return(MODE1)
            }
        }
    }

    return(as.vector(lapply(DF, MODE2)))
}

Давайте попробуем:

MODE(mtcars)
MODE(CO2)
MODE(ToothGrowth)
MODE(InsectSprays)
...