C’è una funzione integrata per trovare la modalità?

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

Un’altra soluzione, che funziona sia per i dati numerici che per i caratteri / fattori:

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

Sulla mia piccola macchina dinky, in grado di generare e trovare la modalità di un vettore intero 10M in circa mezzo secondo.

Esiste la modalità pacchetto che fornisce stimatori della modalità di dati unimodali (e talvolta multimodali) e valori delle modalità delle distribuzioni di probabilità usuali.

 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

trovato questo sulla mailing list, spero sia utile. È anche quello che stavo pensando in ogni caso. Avrai voglia di tabella () i dati, ordinare e quindi scegliere il nome. È hackish ma dovrebbe funzionare.

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

Ho trovato Ken Williams post sopra per essere fantastico, ho aggiunto alcune righe per tenere conto dei valori di NA e ne ho fatto 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)))]) } 

Un modo rapido e sporco di stimare la modalità di un vettore di numeri che si ritiene provengano da una continua distribuzione univariata (ad esempio una distribuzione normale) sta definendo e utilizzando 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 

La seguente funzione è disponibile in tre forms:

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

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

Ecco un’altra soluzione:

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

Non posso ancora votare, ma la risposta di Rasmus Bååth è ciò che stavo cercando. Tuttavia, lo modificherei un po ‘permettendomi di controbilanciare la distribuzione, ad esempio valori fro 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 che potresti non voler limitare tutta la tua distribuzione, quindi impostare da = - "GRANDE NUMERO", a = "GRANDE NUMERO"

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) 

Una piccola modifica alla risposta di Ken Williams, aggiungendo i parametri facoltativi na.rm e return_multiple .

A differenza delle risposte basate su names() , questa risposta mantiene il tipo di dati di x nei 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 mostrare 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.

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

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

Basato sulla funzione di @ Chris per calcolare la modalità o le metriche correlate, utilizzando comunque 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 nomi di method 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 la performance è ottimizzata, usando 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 output che causano solo un piccolo overhead: Confronto delle funzioni Mode

R ha così tanti pacchetti aggiuntivi che alcuni potrebbero fornire la modalità [statistica] di una lista numerica / serie / vettore.

Tuttavia, la libreria standard di R non sembra avere un metodo così integrato! Un modo per ovviare a questo è usare un costrutto come il seguente (e per trasformarlo in una funzione se si usa 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 prendere in considerazione 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 R di kickstarting
Ciò sembra confermare che (almeno fino alla stesura di questa lezione) non c’è una funzione di modo in R (beh … mode () come hai scoperto è usata per affermare il tipo di variabili).

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

Funziona abbastanza bene

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

Mentre mi piace la semplice funzione di Ken Williams, vorrei recuperare le modalità multiple se esistono. Con questo in mente, 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)) )] } 

Stavo osservando tutte queste opzioni e ho iniziato a interrogarmi sulle loro caratteristiche e prestazioni relative, quindi ho fatto alcuni test. Nel caso in cui qualcun altro sia curioso della stessa cosa, sto condividendo i miei risultati qui.

Non volendo preoccuparmi di tutte le funzioni pubblicate qui, ho scelto di focalizzare l’attenzione su un campione basato su alcuni criteri: la funzione dovrebbe funzionare su entrambi i vettori, i fattori, i vettori logici e numerici, dovrebbe trattare in modo appropriato le NA e altri valori problematici, e l’output dovrebbe essere ‘sensato’, cioè nessun numero come carattere o altro tipo di stupidità.

Ho anche aggiunto una mia funzione, che si basa sulla stessa idea razionale di Chrispy, tranne che per adattarla a 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 serie di dati di test, attraverso microbenchmark . I nomi delle funzioni si riferiscono ai rispettivi autori:

inserisci la descrizione dell'immagine qui

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

In termini di velocità, la versione di Kens vince facilmente, ma è anche l'unica di queste che riporterà solo una modalità, non importa quanti 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 touch. Penso anche che sia interessante il modo in cui alcune funzioni sono influenzate da un numero maggiore di valori unici, mentre altri non lo sono. Non ho studiato il codice in dettaglio per capire perché, oltre all'eliminazione logica / numerica come causa.

Ci sono più soluzioni fornite per questo. Ho controllato il primo e dopo ho scritto il mio. Pubblicalo qui se aiuta qualcuno:

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

Proviamo con qualche esempio. Sto prendendo il set di dati iris . Consente di testare con dati numerici

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

che è ansible verificare è 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 conservare il tipo di input. In tal caso, la funzione modalità 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.

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

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

Vorrei usare la funzione density () 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 di dati. Prestare attenzione al paremetro di regolazione della funzione di densità che regola la levigatura.

Un’altra ansible 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 

Scusate, potrei prenderlo troppo semplice, ma questo non fa il lavoro? (in 1,3 secondi per i valori 1E6 sulla mia macchina):

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

Devi solo sostituire "round (rnorm (1e6), 2)" con il tuo vettore.

Puoi anche calcolare il numero di volte in cui un’istanza è avvenuta nel tuo set e trovare il numero massimo. per esempio

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

Potrebbe provare la seguente funzione:

  1. trasforma valori numerici in fattore
  2. usa summary () per ottenere la tabella delle frequenze
  3. return mode l’indice la cui frequenza è la più grande
  4. trasformare 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) } 

La modalità di calcolo è principalmente in caso di variabile fattore che 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 per le funzioni integrate di per sé senza la funzione di scrittura.

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

Ecco la mia versione inclusa la frazione. Devo dire che voi ragazzi mi avete dato tante nuove soluzioni semplici e intelligenti qui. Molte grazie!

 get_mode < - function(v) { mode <- table(v) %>% as_data_frame() %>% mutate(frac = n/sum(n)) %>% filter(n == max(n)) return(list("mode_var" = mode$v, "n" = mode$n, "var_frac" = mode$frac)) } get_mode(c(1,1,1,1,1,1,1,1,1,2,2,2,22,2,2,2,2,3234,3,4,545,343,56,676,76,764565,67,676,69,879,8978,9784,765,342,5236,43756,76,6,546)) $mode_var [1] "1" $n [1] 9 $var_frac [1] 0.2307692 

Un modo semplice per calcolare la MODALITÀ di un vettore ‘v’ contenente valori discreti è:

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