Esiste una funzione integrata per trovare la modalità?


392

In R, mean()e median()sono funzioni standard che fanno ciò che ti aspetteresti. mode()indica la modalità di archiviazione interna dell'oggetto, non il valore più frequente nel suo argomento. Ma esiste una funzione di libreria standard che implementa la modalità statistica per un vettore (o elenco)?


4
Devi chiarire se i tuoi dati sono numeri interi, numerici, fattore ...? La stima della modalità per i numeri sarà diversa e utilizza intervalli. Vedi modeest
smci,

2
Perché R non ha una funzione integrata per la modalità? Perché R considera modela stessa funzione class?
Corey Levinson,

Risposte:


400

Un'altra soluzione, che funziona sia con dati numerici sia con dati carattere / fattore:

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

Sulla mia piccola macchina viziosa, che può generare e trovare la modalità di un vettore intero 10M in circa mezzo secondo.

Se il tuo set di dati potrebbe avere più modalità, la soluzione precedente utilizza lo stesso approccio which.maxe restituisce il valore che appare per primo della serie di modalità. Per restituire tutte le modalità, utilizzare questa variante (da @digEmAll nei commenti):

Modes <- function(x) {
  ux <- unique(x)
  tab <- tabulate(match(x, ux))
  ux[tab == max(tab)]
}

7
Funziona anche per i logici! Conserva il tipo di dati per tutti i tipi di vettori (a differenza di alcune implementazioni in altre risposte).
DavidC

39
Ciò non restituisce tutte le modalità in caso di set di dati multimodale (ad es c(1,1,2,2).). Dovresti cambiare l'ultima riga con:tab <- tabulate(match(x, ux)); ux[tab == max(tab)]
digEmAll

6
@verybadatthis Per questo, si sostituirà ux[which.max(tabulate(match(x, ux)))]con solo max(tabulate(match(x, ux))).
Ken Williams,

4
Notate che Mode(1:3)1e Mode(3:1)3, quindi Mode restituisce l'elemento più frequente o il primo se tutti sono unici.
Enrique Pérez Herrero,

2
Come ha detto Enrique: questo fallisce quando non c'è modalità, e invece ti dà l'impressione che il primo valore sia la modalità. Sarebbe stato molto meglio se fosse tornato 0o NAin quei casi.
not2qubit,

66

Esiste un pacchetto modeestche fornisce stimatori della modalità di dati univodati unimodali (e talvolta multimodali) e valori delle modalità delle consuete distribuzioni di probabilità.

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

Per maggiori informazioni vedi questa pagina


7
Quindi, per ottenere solo il valore della modalità, mfv(mySamples)[1]. L' 1essere importante in quanto restituisce effettivamente il valore più frequente s .
atomici

non sembra funzionare in questo esempio: libreria (modeest) a <- rnorm (50, 30, 2) b <- rnorm (100, 35, 2) c <- rnorm (20, 37, 2) temperaturaºC <- c (a, b, c) hist (temperatureºC) #mline abline (v = mean (temperatureºC), col = "red", lwd = 2) #median abline (v = median (temperatureºC), col = "black", lwd = 2) #mode abline (v = mlv (temperaturaºC, metodo = "mfv") [1], col = "orange", lwd = 2)
Agus camacho

1
@atomicules: con [1] ottieni solo la prima modalità. Per la distribuzione n-modale bimodale o generale avresti bisogno solomfv(mySamples)
petzi,

1
Per R versione 3.6.0, dice che la funzione 'non è stata in grado di trovare la funzione "mlv"' e lo stesso errore quando ho provato mfv (mysamples). È ammortizzato?
Dr Nisha Arora,

@DrNishaArora: hai scaricato il pacchetto 'modeest'?
Petzi,

59

trovato questo sulla mailing list r, spero che sia utile. È anche quello che stavo pensando comunque. Ti consigliamo di tabella () i dati, ordinare e quindi scegliere il nome. È hacker ma dovrebbe funzionare.

names(sort(-table(x)))[1]

6
Anche questa è una soluzione intelligente. Presenta alcuni inconvenienti: l'algoritmo di ordinamento può richiedere più spazio e tempo rispetto agli approcci basati su max () (=> da evitare per elenchi di campioni più grandi). Anche l'uscita è di modalità (scusate il gioco di parole / ambiguità) "carattere" non "numerico". E, naturalmente, la necessità di testare la distribuzione multimodale richiederebbe in genere la memorizzazione della tabella ordinata per evitare di ridurla nuovamente.
mjv,

2
Ho misurato il tempo di esecuzione con un fattore di 1e6 elementi e questa soluzione è stata più veloce della risposta accettata di quasi il fattore 3!
vonjd,

L'ho appena convertito in numero usando as.numeric (). Funziona perfettamente. Grazie!
Abhishek Singh,

47

Ho trovato il post di Ken Williams qui sopra eccezionale, ho aggiunto alcune righe per tenere conto dei valori di NA e l'ho reso una funzione per facilità.

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

Ho trovato un paio di accelerazioni a questo, vedi la risposta sotto.
Dan Houghton,

33

Un modo rapido e sporco di stimare la modalità di un vettore di numeri che ritieni provenga da una continua distribuzione univariata (ad esempio una distribuzione normale) sta definendo e usando la seguente funzione:

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

Quindi per ottenere la stima della modalità:

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
Solo una nota su questo: puoi ottenere una "modalità" di qualsiasi gruppo di numeri continui in questo modo. Non è necessario che i dati provengano da una normale distribuzione per funzionare. Ecco un esempio prendendo i numeri da una distribuzione uniforme. set.seed(1); a<-runif(100); mode<-density(a)$x[which.max(density(a)$y)]; abline(v=mode)
Jota,

error in density.default(x, from = from, to = to) : need at least 2 points to select a bandwidth automatically
Sergio,

@xhie Quel messaggio di errore ti dice tutto ciò che devi sapere. Se hai solo un punto, devi impostare manualmente la larghezza di banda durante la chiamata density. Tuttavia, se hai solo un punto dati, il valore di quel punto dati sarà probabilmente la tua ipotesi migliore per la modalità ...
Rasmus Bååth,

Hai ragione, ma ho aggiunto solo una modifica: estimate_mode <- function(x) { if (length(x)>1){ d <- density(x) d$x[which.max(d$y)] }else{ x } } sto testando il metodo per stimare il vento in direzione predominante, anziché la media della direzione usando la media vettoriale con pacchetto circolare. I ', lavorando con punti sopra un grado poligonale, quindi a volte c'è solo un punto con direzione. Grazie!
Sergio,

@xhie Sembra ragionevole :)
Rasmus Bååth,

14

La seguente funzione è disponibile in tre forme:

method = "mode" [default]: calcola la modalità per un vettore unimodale, altrimenti restituisce un NA
method = "nmodes": calcola il numero di modalità nel vettore
method = "modes": elenca tutte le modalità per un unimodale o polimodale vettore

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

Nella tua descrizione di queste funzioni hai scambiato "mode" e "nmodes". Vedi il codice In realtà, "nmodes" restituisce il vettore di valori e "mode" restituisce il numero di modalità. Nondimeno la tua funzione è l'anima migliore per trovare le modalità che ho visto finora.
Grzegorz Adam Kowalski

Mille grazie per il commento. "nmode" e "mode" ora dovrebbero comportarsi come previsto.
Chris

La tua funzione funziona quasi, tranne quando ogni valore si verifica ugualmente spesso usando method = 'modes'. Quindi la funzione restituisce tutti i valori univoci, tuttavia in realtà non esiste una modalità, quindi dovrebbe restituire NAinvece. Aggiungerò un'altra risposta contenente una versione leggermente ottimizzata della tua funzione, grazie per l'ispirazione!
hugovdberg,

L'unica volta in cui un vettore numerico non vuoto dovrebbe normalmente generare un NA con questa funzione è quando si utilizza il metodo predefinito su un vettore polimodale. La modalità di una semplice sequenza di numeri come 1,2,3,4 è in realtà tutti quei numeri nella sequenza, quindi per sequenze simili le "modalità" si stanno comportando come previsto. es. modeave (c (1,2,3,4), method = "modes") restituisce [1] 1 2 3 4 Indipendentemente da ciò, sarei molto interessato a vedere la funzione ottimizzata in quanto è abbastanza ad alta intensità di risorse nella sua stato attuale
Chris

Per una versione più efficiente di questa funzione, vedi il post di @ hugovdberg sopra :)
Chris

10

Ecco un'altra soluzione:

freq <- tapply(mySamples,mySamples,length)
#or freq <- table(mySamples)
as.numeric(names(freq)[which.max(freq)])

È possibile sostituire la prima riga con la tabella.
Jonathan Chang,

Pensavo che "tapply" fosse più efficiente di "table", ma entrambi usano un ciclo for. Penso che la soluzione con tabella sia equivalente. Aggiorno la risposta.
teucer

9

Non posso ancora votare, ma la risposta di Rasmus Bååth è ciò che stavo cercando. Tuttavia, lo modificherei un po 'permettendo di contravvenire alla distribuzione, ad esempio per valori solo tra 0 e 1.

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

Siamo consapevoli del fatto che potresti non voler limitare la tua distribuzione, quindi impostare da = - "BIG NUMBER", a = "BIG NUMBER"


error in density.default(x, from = from, to = to) : need at least 2 points to select a bandwidth automatically
Sergio,

x dovrebbe essere un vettore
AleRuete,

8

Una piccola modifica alla risposta di Ken Williams, aggiungendo parametri opzionali na.rme return_multiple.

A differenza delle risposte invocate names(), questa risposta mantiene il tipo di dati xnei valori restituiti.

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

Per dimostrarlo funziona con i parametri opzionali e mantiene il tipo di dati:

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"

Grazie a @Frank per la semplificazione.


7

Ho scritto il seguente codice per generare la modalità.

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

Proviamolo:

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

6

Basato sulla funzione di @ Chris per calcolare la modalità o le relative metriche, tuttavia utilizzando il metodo di Ken Williams per calcolare le frequenze. Questo fornisce una correzione per il caso di nessuna modalità (tutti gli elementi ugualmente frequenti) e alcuni methodnomi più leggibili .

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'")
}

Poiché utilizza il metodo di Ken per calcolare le frequenze, anche le prestazioni sono ottimizzate, utilizzando il post di AkselA ho confrontato alcune delle risposte precedenti per mostrare come la mia funzione è vicina a quella di Ken, con i condizionali per le varie opzioni di uscita che causano solo lievi spese generali: Confronto tra le funzioni della modalità


Il codice che presenti sembra essere una copia più o meno diretta della Modefunzione trovata nel pracmapacchetto. Ti interessa spiegare?
Aksel,

Veramente? Apparentemente non sono l'unico a pensare che questo sia un buon modo per calcolare la modalità, ma sinceramente non lo sapevo (non avevo mai conosciuto quel pacchetto prima d'ora). Ho ripulito la funzione di Chris e l'ho migliorata sfruttando la versione di Ken, e se assomiglia al codice di qualcun altro che è puramente casuale.
hugovdberg,

L'ho esaminato proprio ora, ma a quale versione del pracmapacchetto ti riferisci? La versione 1.9.3 ha un'implementazione completamente diversa per quanto posso vedere.
hugovdberg,

2
Bel emendamento alla funzione. Dopo qualche ulteriore lettura, sono portato alla conclusione che non vi è consenso sul fatto che le distribuzioni uniformi o monofrequenze abbiano nodi, alcune fonti affermano che l'elenco delle modalità sono le distribuzioni stesse, altri che non esiste un nodo. L'unico accordo è che la produzione di un elenco di modalità per tali distribuzioni non è né molto istruttiva né particolarmente significativa. Se desideri che la funzione sopra descritta produca modalità in questi casi, quindi rimuovi la riga: nmodes <- ifelse (nmodes == n, 0L, nmodes)
Chris

1
@greendiod scusa, ho perso il tuo commento. È disponibile tramite questa sintesi
hugovdberg

6

Questo hack dovrebbe funzionare bene. Ti dà il valore e il conteggio della modalità:

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

3

R ha così tanti pacchetti aggiuntivi che alcuni di essi potrebbero fornire la modalità [statistica] di un elenco numerico / serie / vettore.

Tuttavia, la libreria standard di R in sé non sembra avere un metodo così integrato! Un modo per aggirare questo è usare un costrutto come il seguente (e trasformarlo in una funzione se usi spesso ...):

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

Per un elenco di campioni più grande, si dovrebbe considerare l'utilizzo di una variabile temporanea per il valore max (tabSmpl) (non so che R lo ottimizzerebbe automaticamente)

Riferimento: vedi "Che ne dici di mediana e modalità?" in questa lezione di KickStarting R
Questo sembra confermare che (almeno dalla stesura di questa lezione) non c'è una funzione mode in R (beh ... mode () come hai scoperto è usata per affermare il tipo di variabili ).


3

Funziona abbastanza bene

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

3

Ecco una funzione per trovare la modalità:

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

Di seguito è riportato il codice che può essere utilizzato per trovare la modalità di una variabile vettoriale in R.

a <- table([vector])

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

3

Sono disponibili più soluzioni per questo. Ho controllato il primo e dopo ho scritto il mio. Pubblicandolo qui se aiuta qualcuno:

Mode <- function(x){
  y <- data.frame(table(x))
  y[y$Freq == max(y$Freq),1]
}

Proviamo con alcuni esempi. Sto prendendo il irisset di dati. Consente di testare con dati numerici

> Mode(iris$Sepal.Length)
[1] 5

che puoi verificare sia corretto.

Ora l'unico campo non numerico nel set di dati dell'iride (specie) non ha una modalità. Proviamo con il nostro esempio

> test <- c("red","red","green","blue","red")
> Mode(test)
[1] red

MODIFICARE

Come menzionato nei commenti, l'utente potrebbe voler preservare il tipo di input. Nel qual caso la funzione mode può essere modificata in:

Mode <- function(x){
  y <- data.frame(table(x))
  z <- y[y$Freq == max(y$Freq),1]
  as(as.character(z),class(x))
}

L'ultima riga della funzione costringe semplicemente il valore della modalità finale al tipo di input originale.


Questo restituisce un fattore, mentre l'utente probabilmente vuole preservare il tipo di input. Forse aggiungere un passaggio intermedioy[,1] <- sort(unique(x))
Frank,

2

Vorrei usare la funzione densità () per identificare un massimo livellato di una distribuzione (possibilmente continua):

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

dove x è la raccolta dei dati. Prestare attenzione al paremetro di regolazione della funzione di densità che regola il livellamento.


2

Mentre mi piace la semplice funzione di Ken Williams, vorrei recuperare le diverse modalità se esistono. Tenendo presente ciò, utilizzo la seguente funzione che restituisce un elenco delle modalità, se multiple o singole.

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

Sarebbe più coerente per l'uso programmatico se restituisse sempre un elenco - di lunghezza 1 se esiste solo una modalità
asac

Questo è un valido punto @ antoine-sac. Quello che mi piace di questa soluzione è il vettore che viene restituito lascia le risposte facilmente indirizzabili. Basta indirizzare l'output della funzione: r <- mode (c (2, 2, 3, 3)) con le modalità disponibili su r [1] e r [2]. Comunque, fai un buon punto !!
RandallShanePhD,

È proprio qui che la tua soluzione non è all'altezza. Se moderestituisce un elenco con più valori, allora r [1] non è il primo valore; è invece un elenco di lunghezza 1 contenente il primo valore e devi fare r [[1]] per ottenere la prima modalità come un numero e non un elenco. Ora, quando esiste una modalità singola, la tua r non è un elenco, quindi r [1] funziona, motivo per cui ho pensato che fosse incoerente. Ma poiché r [[1]] funziona anche quando r è un vettore semplice, in realtà esiste una coerenza che non mi ero reso conto che puoi sempre usare [[per accedere agli elementi.
asac,

2

Stavo esaminando tutte queste opzioni e ho iniziato a chiedermi quali fossero le loro caratteristiche e prestazioni, quindi ho fatto alcuni test. Nel caso in cui qualcun altro fosse curioso della stessa cosa, sto condividendo i miei risultati qui.

Non volendo preoccuparmi di tutte le funzioni pubblicate qui, ho scelto di concentrarmi su un campione basato su alcuni criteri: la funzione dovrebbe funzionare su caratteri, fattori, vettori logici e numerici, dovrebbe occuparsi in modo appropriato di NA e altri valori problematici, e l'output dovrebbe essere "sensato", cioè nessun valore numerico come carattere o altra stupidità simile.

Ho anche aggiunto una mia funzione, che si basa sulla stessa rleidea di Chrispy, tranne adattata per un uso più generale:

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

Ho finito per eseguire cinque funzioni, su due set di dati di test, attraverso microbenchmark. I nomi delle funzioni si riferiscono ai rispettivi autori:

inserisci qui la descrizione dell'immagine

La funzione di Chris è stata impostata su method="modes"e na.rm=TRUEper impostazione predefinita per renderla più comparabile, ma a parte questo sono state utilizzate le funzioni presentate qui dai loro autori.

Per quanto riguarda la velocità, solo la versione di Kens vince facilmente, ma è anche l'unica di queste che segnalerà solo una modalità, non importa quante ce ne siano davvero. Come spesso accade, c'è un compromesso tra velocità e versatilità. In method="mode", la versione di Chris restituirà un valore se esiste una modalità, altrimenti NA. Penso che sia un bel tocco. Penso anche che sia interessante come alcune funzioni siano influenzate da un numero crescente di valori univoci, mentre altre non sono altrettanto. Non ho studiato il codice in dettaglio per capire perché, oltre a eliminare logico / numerico come causa.


2

La modalità non può essere utile in tutte le situazioni. Quindi la funzione dovrebbe affrontare questa situazione. Prova la seguente funzione.

Mode <- function(v) {
  # checking unique numbers in the input
  uniqv <- unique(v)
  # frquency of most occured value in the input data
  m1 <- max(tabulate(match(v, uniqv)))
  n <- length(tabulate(match(v, uniqv)))
  # if all elements are same
  same_val_check <- all(diff(v) == 0)
  if(same_val_check == F){
    # frquency of second most occured value in the input data
    m2 <- sort(tabulate(match(v, uniqv)),partial=n-1)[n-1]
    if (m1 != m2) {
      # Returning the most repeated value
      mode <- uniqv[which.max(tabulate(match(v, uniqv)))]
    } else{
      mode <- "Two or more values have same frequency. So mode can't be calculated."
    }
  } else {
    # if all elements are same
    mode <- unique(v)
  }
  return(mode)
}

Produzione,

x1 <- c(1,2,3,3,3,4,5)
Mode(x1)
# [1] 3

x2 <- c(1,2,3,4,5)
Mode(x2)
# [1] "Two or more varibles have same frequency. So mode can't be calculated."

x3 <- c(1,1,2,3,3,4,5)
Mode(x3)
# [1] "Two or more values have same frequency. So mode can't be calculated."

Siamo spiacenti, non vedo come questo aggiunge qualcosa di nuovo a ciò che è già stato pubblicato. Inoltre, l'output sembra incoerente con la funzione sopra.
not2qubit

2

Questo si basa sulla risposta di jprockbelly, aggiungendo una velocità per vettori molto brevi. Ciò è utile quando si applica la modalità a un data.frame o un datatable con molti piccoli gruppi:

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

1

Un'altra semplice opzione che fornisce tutti i valori ordinati per frequenza è usare rle:

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

1

Un'altra possibile soluzione:

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

Uso:

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

Produzione:

   user  system elapsed 
   0.32    0.00    0.31 

1

Suppongo che le tue osservazioni siano classi da numeri reali e ti aspetti che la modalità sia 2.5 quando le tue osservazioni sono 2, 2, 3 e 3, quindi potresti stimare la modalità con mode = l1 + i * (f1-f0) / (2f1 - f0 - f2)cui l1 .. limite inferiore della classe più frequente, f1 . .frequency di classe più frequente, f0 ..frequency delle classi prima classe più frequente, f2 ..frequency delle classi dopo classe più frequente ed i ..Class intervallo come indicato ad esempio in 1 , 2 , 3 :

#Small Example
x <- c(2,2,3,3) #Observations
i <- 1          #Class interval

z <- hist(x, breaks = seq(min(x)-1.5*i, max(x)+1.5*i, i), plot=F) #Calculate frequency of classes
mf <- which.max(z$counts)   #index of most frequent class
zc <- z$counts
z$breaks[mf] + i * (zc[mf] - zc[mf-1]) / (2*zc[mf] - zc[mf-1] - zc[mf+1])  #gives you the mode of 2.5


#Larger Example
set.seed(0)
i <- 5          #Class interval
x <- round(rnorm(100,mean=100,sd=10)/i)*i #Observations

z <- hist(x, breaks = seq(min(x)-1.5*i, max(x)+1.5*i, i), plot=F)
mf <- which.max(z$counts)
zc <- z$counts
z$breaks[mf] + i * (zc[mf] - zc[mf-1]) / (2*zc[mf] - zc[mf-1] - zc[mf+1])  #gives you the mode of 99.5

Se desideri il livello più frequente e hai più di un livello più frequente, puoi ottenerli tutti ad es. Con:

x <- c(2,2,3,5,5)
names(which(max(table(x))==table(x)))
#"2" "5"

1

Aggiunta di un possibile approccio data.table

library(data.table)
#for single mode
dtmode <- function(x) x[which.max(data.table::rowid(x))]

#for multiple modes
dtmodes <- function(x) x[{r <- rowid(x); r==max(r)}]

1

Ecco alcuni modi in cui puoi farlo nel tempo di esecuzione di Theta (N)

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

0

Potrebbe provare la seguente funzione:

  1. trasforma valori numerici in fattore
  2. usa il sommario () per ottenere la tabella delle frequenze
  3. modalità di ritorno l'indice la cui frequenza è la più grande
  4. Trasforma il fattore in numerico anche se ci sono più di 1 modalità, questa funzione funziona bene!
mode <- function(x){
  y <- as.factor(x)
  freq <- summary(y)
  mode <- names(freq)[freq[names(freq)] == max(freq)]
  as.numeric(mode)
}

0

La modalità di calcolo è principalmente in caso di variabile fattore, quindi possiamo usare

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

HouseVotes84 è un set di dati disponibile nel pacchetto 'mlbench'.

darà il valore massimo dell'etichetta. è più facile da usare dalle funzioni integrate senza scrivere la funzione.


0

Mi sembra che se una collezione ha una modalità, i suoi elementi possono essere mappati uno a uno con i numeri naturali. Pertanto, il problema di trovare la modalità si riduce alla produzione di tale mappatura, alla ricerca della modalità dei valori mappati, quindi alla mappatura su alcuni degli elementi della raccolta. (Trattare conNA verifica in fase di mappatura).

Ho una histogramfunzione che opera su un principio simile. (Le funzioni e gli operatori speciali utilizzati nel codice qui presentato devono essere definiti in Shapiro e / o neatOveRse . Le parti di Shapiro e neatOveRse duplicate nel presente documento sono così duplicate con l'autorizzazione; i frammenti duplicati possono essere utilizzati in base ai termini di questo sito. ) R pseudocodice per histogramis

.histogram <- function (i)
        if (i %|% is.empty) integer() else
        vapply2(i %|% max %|% seqN, `==` %<=% i %O% sum)

histogram <- function(i) i %|% rmna %|% .histogram

(Gli speciali operatori binari eseguono piping , curry e composizione ) Ho anche una maxlocfunzione, che è simile a which.max, ma restituisce tutti i massimi assoluti di un vettore. R pseudocodice per maxlocis

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

Poi

imode <- histogram %O% maxloc

e

x %|% map %|% imode %|% unmap

calcolerà la modalità di qualsiasi raccolta, a condizione che siano definite le funzioni map-ping e unmap-ping appropriate .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.