Есть ли встроенная функция для нахождения режима?

254

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

  • 4
    Вам необходимо уточнить, являются ли ваши данные целочисленными, числовыми, множителями ...? Оценка режима для чисел будет отличаться, и использовать интервалы. См скромнее
  • 0
    Почему у R нет встроенной функции для режима? Почему R считает mode таким же, как class функций?
Теги:
statistics
r-faq

26 ответов

279
Лучший ответ

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

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

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

  • 5
    Также работает для логики! Сохраняет тип данных для всех типов векторов (в отличие от некоторых реализаций в других ответах).
  • 34
    Это не возвращает все режимы в случае мультимодального набора данных (например, c(1,1,2,2) ). Вы должны изменить свою последнюю строку следующим образом: tab <- tabulate(match(x, ux)); ux[tab == max(tab)]
Показать ещё 8 комментариев
53

Существует пакет 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 modal skewness: -0.1 
Call: mlv.default(x = mySamples, method = "mfv")

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

  • 6
    Таким образом, чтобы просто получить значение режима, mfv(mySamples)[1] . Значение 1 важно, так как оно возвращает наиболее частое значение s .
  • 0
    в данном примере это не работает: библиотека (модест) a <- rnorm (50, 30, 2) b <- rnorm (100, 35, 2) c <- rnorm (20, 37, 2) температура ºC <- c (a, b, c) hist (температура ºC) # средняя аблиция (v = среднее (температура ºC), col = «красный», lwd = 2) # средняя аблайн (v = медиана (температура ºC), col = «черная», lwd = 2) # abline режима (v = mlv (температура ºC, метод = "mfv") [1], col = "оранжевый", lwd = 2)
Показать ещё 1 комментарий
40

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

names(sort(-table(x)))[1]
  • 6
    Это умная работа, а также. У него есть несколько недостатков: алгоритм сортировки может занимать больше места и времени, чем подходы, основанные на max () (=>, которых следует избегать для больших выборочных списков). Также выход имеет режим (простите за каламбур / неоднозначность) «символ», а не «числовой». И, конечно же, необходимость проверки мультимодального распределения обычно требует хранения отсортированной таблицы, чтобы избежать ее повторного сжатия.
  • 1
    Я измерил время выполнения с коэффициентом 1e6, и это решение оказалось быстрее, чем принятый ответ, почти в 3 раза!
Показать ещё 1 комментарий
27

Я нашел пост Кен Уильямса выше, я добавил несколько строк для учета значений 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)))])
}
  • 0
    Я нашел несколько ускорений, см. Ответ ниже.
23

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

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
  • 3
    Просто обратите внимание на это: вы можете получить «режим» любой группы непрерывных чисел таким образом. Данные не должны поступать из нормального распределения для работы. Вот пример, берущий числа из равномерного распределения. set.seed(1); a<-runif(100); mode<-density(a)$x[which.max(density(a)$y)]; abline(v=mode)
  • 0
    error in density.default(x, from = from, to = to) : need at least 2 points to select a bandwidth automatically
Показать ещё 3 комментария
13

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

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

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()
}
  • 0
    В вашем описании этой функции вы поменялись местами "mode" и "nmodes". Смотрите код. На самом деле, «nmodes» возвращает вектор значений, а «mode» возвращает количество режимов. Тем не менее, ваша функция - самая лучшая задача для поиска режимов, которые я видел до сих пор.
  • 0
    Большое спасибо за комментарий. «nmode» и «mode» теперь должны вести себя как положено.
Показать ещё 3 комментария
10

Здесь другое решение:

freq <- tapply(mySamples,mySamples,length)
#or freq <- table(mySamples)
as.numeric(names(freq)[which.max(freq)])
  • 0
    Вы можете заменить первую строку с таблицей.
  • 0
    Я думал, что «tapply» более эффективен, чем «table», но они оба используют цикл for. Я думаю, что решение с таблицей эквивалентно. Я обновляю ответ.
8

Я не могу голосовать, но ответ Rasmus Bååth - это то, что я искал. Тем не менее, я бы немного изменил его, чтобы ограничить распространение, например, значениями от 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)]
}

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

  • 0
    error in density.default(x, from = from, to = to) : need at least 2 points to select a bandwidth automatically
  • 0
    х должен быть вектором
6

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

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)
4

Этот хак должен работать нормально. Дает вам значение, а также счетчик режима:

Mode <- function(x){
a = table(x) # x is a vector
return(a[which.max(a)])
}
4

На основе функции @Chris для вычисления режима или связанных показателей, однако используя метод Кен Уильямса для расчета частот. Это обеспечивает исправление для случая без режимов (все элементы одинаково часты) и некоторые более читаемые имена method.

Mode <- function(x, method = "one", na.rm = FALSE) {
  x <- unlist(x)
  if (na.rm) {
    x <- x[!is.na(x)]
  }

  # Get unique values
  ux <- unique(x)
  n <- length(ux)

  # Get frequencies of all unique values
  frequencies <- tabulate(match(x, ux))
  modes <- frequencies == max(frequencies)

  # Determine number of modes
  nmodes <- sum(modes)
  nmodes <- ifelse(nmodes==n, 0L, nmodes)

  if (method %in% c("one", "mode", "") | is.na(method)) {
    # Return NA if not exactly one mode, else return the mode
    if (nmodes != 1) {
      return(NA)
    } else {
      return(ux[which(modes)])
    }
  } else if (method %in% c("n", "nmodes")) {
    # Return the number of modes
    return(nmodes)
  } else if (method %in% c("all", "modes")) {
    # Return NA if no modes exist, else return all modes
    if (nmodes > 0) {
      return(ux[which(modes)])
    } else {
      return(NA)
    }
  }
  warning("Warning: method not recognised.  Valid methods are 'one'/'mode' [default], 'n'/'nmodes' and 'all'/'modes'")
}

Поскольку он использует метод Ken для расчета частот, производительность также оптимизирована, используя AkselA post I, сравнивая некоторые из предыдущих ответов, чтобы показать, насколько моя функция близка к производительности в Ken, с условными значениями для разных вариантов вывода, вызывающих только незначительные накладные расходы: Изображение 4310

  • 0
    Код, который вы представляете, кажется более или менее прямой копией функции Mode найденной в пакете pracma . Хотите объяснить?
  • 0
    В самом деле? Очевидно, я не единственный, кто считает, что это хороший способ рассчитать режим, но я, честно говоря, этого не знал (никогда раньше не знал этот пакет). Я очистил функцию Криса и улучшил ее, используя версию Кена, и, если она напоминает чужой код, это чисто случайное совпадение.
Показать ещё 7 комментариев
3

Вот функция, чтобы найти режим:

mode <- function(x) {
  unique_val <- unique(x)
  counts <- vector()
  for (i in 1:length(unique_val)) {
    counts[i] <- length(which(x==unique_val[i]))
  }
  position <- c(which(counts==max(counts)))
  if (mean(counts)==max(counts)) 
    mode_x <- 'Mode does not exist'
  else 
    mode_x <- unique_val[position]
  return(mode_x)
}
3

R имеет так много дополнительных пакетов, что некоторые из них могут обеспечить [статистический] режим числового списка/серии/вектора.

Однако стандартная библиотека R сама по себе не имеет такого встроенного метода! Один из способов обойти это - использовать некоторую конструкцию следующим образом (и превратить ее в функцию, если вы часто используете...):

mySamples <- c(19, 4, 5, 7, 29, 19, 29, 13, 25, 19)
tabSmpl<-tabulate(mySamples)
SmplMode<-which(tabSmpl== max(tabSmpl))
if(sum(tabSmpl == max(tabSmpl))>1) SmplMode<-NA
> SmplMode
[1] 19

Для большего списка образцов следует рассмотреть возможность использования временной переменной для значения max (tabSmpl) (я не знаю, что R автоматически оптимизирует это)

Ссылка: см. "Как насчет медианы и режима?" в этом Урок KickStarting R
Это, по-видимому, подтверждает, что (по крайней мере, на момент написания этого урока) в R нет функции режима (ну... mode(), как вы выяснили, используется для утверждения типа переменных).

2

Небольшая модификация ответа Кен Уильямса, добавляющая необязательные параметры 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 для упрощения.

2

Я просматривал все эти варианты и начал задаваться вопросом об их относительных функциях и характеристиках, поэтому я сделал несколько тестов. В случае, если кому-то еще интересны то же самое, я делюсь своими результатами здесь.

Не желая беспокоиться обо всех функциях, размещенных здесь, я решил сфокусироваться на выборке, основанном на нескольких критериях: функция должна работать как с символьными, так и с факториальными, логическими и числовыми векторами, она должна иметь дело с НС и другими проблемными значения должны быть "разумными", т.е. никакими числами в качестве характера или другой такой глупости.

Я также добавил функцию моего собственного, которая основана на той же идее rle, что и chrispy's, кроме адаптированной для более общего использования:

library(magrittr)

Aksel <- function(x, freq=FALSE) {
    z <- 2
    if (freq) z <- 1:2
    run <- x %>% as.vector %>% sort %>% rle %>% unclass %>% data.frame
    colnames(run) <- c("freq", "value")
    run[which(run$freq==max(run$freq)), z] %>% as.vector   
}

set.seed(2)

F <- sample(c("yes", "no", "maybe", NA), 10, replace=TRUE) %>% factor
Aksel(F)

# [1] maybe yes  

C <- sample(c("Steve", "Jane", "Jonas", "Petra"), 20, replace=TRUE)
Aksel(C, freq=TRUE)

# freq value
#    7 Steve

Я закончил работу с пятью функциями на двух наборах тестовых данных через microbenchmark. Названия функций относятся к их соответствующим авторам:

Изображение 4311

Функция Chris была установлена ​​на method="modes" и na.rm=TRUE по умолчанию, чтобы сделать ее более сопоставимой, но кроме того, что функции были использованы, как представлено здесь их авторами.

В скорости только одна версия Kens выигрывает, но она также является единственной из них, которая будет сообщать только один режим, независимо от того, сколько там действительно. Как это часто бывает, существует компромисс между скоростью и универсальностью. В method="mode" версия Chris вернет значение, если есть один режим, иначе NA. Я думаю, что это приятный штрих. Я также думаю, что интересно, как на некоторые функции влияет большее количество уникальных значений, в то время как другие - не так много. Я не изучил код подробно, чтобы выяснить, почему это, кроме устранения логического/числового в качестве причины.

2

Хотя мне нравится простая функция Кен Уильямса, я хотел бы получить несколько режимов, если они существуют. Имея это в виду, я использую следующую функцию, которая возвращает список режимов, если несколько или одиночный.

rmode <- function(x) {
  x <- sort(x)  
  u <- unique(x)
  y <- lapply(u, function(y) length(x[x==y]))
  u[which( unlist(y) == max(unlist(y)) )]
} 
  • 0
    Было бы более согласованным для программного использования, если бы он всегда возвращал список - длиной 1, если есть только один режим
  • 0
    Это верная точка зрения @ antoine-sac. Что мне нравится в этом решении, так это то, что возвращаемый вектор оставляет ответы легко адресуемыми. Просто обратитесь к выходу функции: r <- режим (c (2, 2, 3, 3)) с режимами, доступными в r [1] и r [2]. Тем не менее, вы делаете хорошую мысль !!
Показать ещё 1 комментарий
2

Это работает довольно хорошо

> a<-c(1,1,2,2,3,3,4,4,5)
> names(table(a))[table(a)==max(table(a))]
1

Другое возможное решение:

Mode <- function(x) {
    if (is.numeric(x)) {
        x_table <- table(x)
        return(as.numeric(names(x_table)[which.max(x_table)]))
    }
}

Использование:

set.seed(100)
v <- sample(x = 1:100, size = 1000000, replace = TRUE)
system.time(Mode(v))

Вывод:

   user  system elapsed 
   0.32    0.00    0.31 
1

Я использовал бы функцию плотности() для определения сглаженного максимума (возможно непрерывного) распределения:

function(x) density(x, 2)$x[density(x, 2)$y == max(density(x, 2)$y)]

где x - сбор данных. Обратите внимание на настраиваемый пареметр функции плотности, который регулирует сглаживание.

1

Еще одна простая опция, которая дает все значения, упорядоченные по частоте, - это использовать rle:

df = as.data.frame(unclass(rle(sort(mySamples))))
df = df[order(-df$lengths),]
head(df)
0

Ниже приведен код, который можно использовать для поиска режима векторной переменной в R.

a <- table([vector])

names(a[a==max(a)])
0

Режим вычисления в основном в случае фактор-переменной, тогда мы можем использовать

labels(table(HouseVotes84$V1)[as.numeric(labels(max(table(HouseVotes84$V1))))])

HouseVotes84 - это набор данных, доступный в пакете "mlbench".

он даст максимальное значение метки. его проще использовать встроенными функциями без записи функции.

0

Можно попробовать следующую функцию:

  • преобразует числовые значения в коэффициент
  • используйте summary() для получения таблицы частот
  • режим возврата индекс, частота которого является наибольшей
  • преобразует коэффициент обратно в числовое, даже существует более одного режима, эта функция работает хорошо!
mode <- function(x){
  y <- as.factor(x)
  freq <- summary(y)
  mode <- names(freq)[freq[names(freq)] == max(freq)]
  as.numeric(mode)
}
0

Вы также можете рассчитать количество раз, когда экземпляр произошел в вашем наборе и найти максимальное число. например.

> temp <- table(as.vector(x))
> names (temp)[temp==max(temp)]
[1] "1"
> as.data.frame(table(x))
r5050 Freq
1     0   13
2     1   15
3     2    6
> 
0

Извините, я могу считать это слишком простым, но разве это не делает работу? (в 1,3 секунды для значений 1E6 на моей машине):

t0 <- Sys.time()
summary(as.factor(round(rnorm(1e6), 2)))[1]
Sys.time()-t0

Вам просто нужно заменить "round (rnorm (1e6), 2)" на ваш вектор.

  • 0
    просто посмотрите на summary.factor - все, что он делает, это оборачивает подход sort(table(...)) в другие ответы.
-1

Простым способом вычисления MODE вектора 'v', содержащего дискретные значения, является:

names(sort(table(v)))[length(sort(table(v)))]

Ещё вопросы

Сообщество Overcoder
Наверх
Меню