Gibt es eine eingebaute Funktion zum Auffinden des Modus?

392

In R mean()und median()sind Standardfunktionen, die das tun, was Sie erwarten. mode()Gibt den internen Speichermodus des Objekts an, nicht den Wert, der in seinem Argument am häufigsten vorkommt. Aber gibt es eine Standardbibliotheksfunktion, die den statistischen Modus für einen Vektor (oder eine Liste) implementiert?

Nick
quelle
4
Sie müssen klären, ob Ihre Daten ganzzahlig, numerisch, faktorisch sind ...? Die Modusschätzung für numerische Daten ist unterschiedlich und verwendet Intervalle. Siehe modeest
smci
2
Warum hat R keine eingebaute Funktion für den Modus? Warum ist R modemit der Funktion identisch class?
Corey Levinson

Antworten:

400

Eine weitere Lösung, die sowohl für numerische als auch für Zeichen- / Faktordaten funktioniert:

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

Auf meiner kleinen Maschine kann das den Modus eines 10M-Integer-Vektors in etwa einer halben Sekunde erzeugen und finden.

Wenn Ihr Datensatz möglicherweise mehrere Modi hat, verwendet die obige Lösung denselben Ansatz wie which.maxund gibt den zuerst erscheinenden Wert des Satzes von Modi zurück. Verwenden Sie diese Variante, um alle Modi zurückzugeben (von @digEmAll in den Kommentaren):

Modes <- function(x) {
  ux <- unique(x)
  tab <- tabulate(match(x, ux))
  ux[tab == max(tab)]
}
Ken Williams
quelle
7
Funktioniert auch für Logicals! Erhält den Datentyp für alle Arten von Vektoren (im Gegensatz zu einigen Implementierungen in anderen Antworten).
DavidC
39
Dies gibt bei einem multimodalen Datensatz (z c(1,1,2,2). B. ) nicht alle Modi zurück . Sie sollten Ihre letzte Zeile ändern mit:tab <- tabulate(match(x, ux)); ux[tab == max(tab)]
digEmAll
6
@verybadatthis Dafür würden Sie ersetzen ux[which.max(tabulate(match(x, ux)))]mit nur max(tabulate(match(x, ux))).
Ken Williams
4
Sie stellen fest, dass Mode(1:3)gibt 1und Mode(3:1)gibt 3, also gibt Mode das häufigste oder das erste Element zurück, wenn alle eindeutig sind.
Enrique Pérez Herrero
2
Wie Enrique sagte: Dies schlägt fehl, wenn es keinen Modus gibt, und vermittelt stattdessen den Eindruck, dass der erste Wert der Modus ist. Wäre viel besser gewesen, wenn es zurückgekehrt wäre 0oder NAin diesen Fällen.
not2qubit
66

Es gibt ein Paket, modeestdas Schätzer für den Modus univariater unimodaler (und manchmal multimodaler) Daten und Werte der Modi üblicher Wahrscheinlichkeitsverteilungen bereitstellt.

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

Weitere Informationen finden Sie auf dieser Seite

George Dontas
quelle
7
Um nur den Moduswert zu erhalten , mfv(mySamples)[1]. Das 1ist wichtig, da es tatsächlich den häufigsten Wert s zurückgibt .
Atomicules
In diesem Beispiel scheint es nicht zu funktionieren: Bibliothek (am besten) a <- rnorm (50, 30, 2) b <- rnorm (100, 35, 2) c <- rnorm (20, 37, 2) TemperaturºC <- c (a, b, c) hist (TemperaturºC) # Mittelwert abline (v = Mittelwert (TemperaturºC), col = "rot", lwd = 2) #median abline (v = Median (TemperaturºC), col = "schwarz", lwd = 2) #mode abline (v = mlv (TemperaturºC, Methode = "mfv") [1], col = "orange", lwd = 2)
Agus camacho
1
@atomicules: Mit [1] erhalten Sie nur den ersten Modus. Für die bimodale oder allgemeine n-modale Verteilung benötigen Sie nurmfv(mySamples)
petzi
1
Für R Version 3.6.0 heißt es, dass die Funktion 'Funktion "mlv" nicht finden konnte' und der gleiche Fehler, als ich mfv (mysamples) ausprobierte. Wird es abgeschrieben?
Dr. Nisha Arora
@DrNishaArora: Hast du das 'modeest'-Paket heruntergeladen?
Petzi
59

fand dies auf der r Mailingliste, hoffe es ist hilfreich. Es ist auch das, was ich sowieso gedacht habe. Sie möchten die Daten tabellieren (), sortieren und dann den Vornamen auswählen. Es ist hackisch, sollte aber funktionieren.

names(sort(-table(x)))[1]
Dan
quelle
6
Das ist auch eine clevere Lösung. Es hat einige Nachteile: Der Sortieralgorithmus kann platz- und zeitaufwendiger sein als max () -basierte Ansätze (=> bei größeren Stichprobenlisten zu vermeiden). Auch die Ausgabe ist von Modus (entschuldigen Sie das Wortspiel / Mehrdeutigkeit) "Zeichen" nicht "numerisch". Und natürlich würde die Notwendigkeit, die multimodale Verteilung zu testen, normalerweise das Speichern der sortierten Tabelle erfordern, um ein erneutes Knirschen zu vermeiden.
MJV
2
Ich habe die Laufzeit mit einem Faktor von 1e6 Elementen gemessen und diese Lösung war um fast Faktor 3 schneller als die akzeptierte Antwort!
vonjd
Ich habe es gerade mit as.numeric () in eine Zahl umgewandelt. Funktioniert einwandfrei. Vielen Dank!
Abhishek Singh
47

Ich fand den obigen Beitrag von Ken Williams großartig. Ich habe ein paar Zeilen hinzugefügt, um die NA-Werte zu berücksichtigen, und ihn zur Vereinfachung gemacht.

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)))])
}
jprockbelly
quelle
Ich habe ein paar Beschleunigungen gefunden, siehe Antwort unten.
Dan Houghton
33

Eine schnelle und schmutzige Methode zur Schätzung des Modus eines Zahlenvektors, von dem Sie glauben, dass er aus einer kontinuierlichen univariaten Verteilung (z. B. einer Normalverteilung) stammt, besteht darin, die folgende Funktion zu definieren und zu verwenden:

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

Um dann die Modusschätzung zu erhalten:

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
Rasmus Bååth
quelle
3
Nur eine Anmerkung zu diesem: Auf diese Weise können Sie einen "Modus" für jede Gruppe von fortlaufenden Zahlen erhalten. Die Daten müssen nicht aus einer Normalverteilung stammen, um zu funktionieren. Hier ist ein Beispiel für Zahlen aus einer gleichmäßigen Verteilung. 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 Diese Fehlermeldung sagt Ihnen alles, was Sie wissen müssen. Wenn Sie nur einen Punkt haben, müssen Sie die Bandbreite beim Anrufen manuell einstellen density. Wenn Sie jedoch nur einen Datenpunkt haben, ist der Wert dieses Datenpunkts wahrscheinlich sowieso Ihre beste Vermutung für den Modus ...
Rasmus Bååth
Sie haben Recht, aber ich habe nur eine Änderung hinzugefügt: estimate_mode <- function(x) { if (length(x)>1){ d <- density(x) d$x[which.max(d$y)] }else{ x } } Ich teste die Methode zur Schätzung des Windes in vorherrschender Richtung anstelle des Richtungsmittelwerts unter Verwendung des vektoriellen Durchschnitts mit kreisförmigem Paket. Ich arbeite mit Punkten über einer Polygonnote, daher gibt es manchmal nur einen Punkt mit Richtung. Vielen Dank!
Sergio
@xhie Klingt vernünftig :)
Rasmus Bååth
14

Die folgende Funktion gibt es in drei Formen:

method = "mode" [Standard]: Berechnet den Modus für einen unimodalen Vektor, andernfalls wird eine NA zurückgegeben.
method = "nmodes": Berechnet die Anzahl der Modi im Vektor.
method = "mode": Listet alle Modi für einen unimodalen oder polymodalen Vektor auf Vektor

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()
}
Chris
quelle
In Ihrer Beschreibung dieser Funktionen haben Sie "Modi" und "Nmodes" vertauscht. Siehe den Code. Tatsächlich gibt "nmodes" einen Vektor von Werten zurück und "mode" gibt die Anzahl von Modi zurück. Trotzdem ist Ihre Funktion die beste Lösung, um Modi zu finden, die ich bisher gesehen habe.
Grzegorz Adam Kowalski
Vielen Dank für den Kommentar. "nmode" und "mode" sollten sich jetzt wie erwartet verhalten.
Chris
Ihre Funktion funktioniert fast, außer wenn jeder Wert gleich häufig mit verwendet wird method = 'modes'. Dann gibt die Funktion alle eindeutigen Werte zurück, es gibt jedoch keinen Modus, sodass sie NAstattdessen zurückgegeben werden sollte. Ich werde eine weitere Antwort hinzufügen, die eine leicht optimierte Version Ihrer Funktion enthält, danke für die Inspiration!
Hugovdberg
Das einzige Mal, dass ein nicht leerer numerischer Vektor normalerweise eine NA mit dieser Funktion erzeugen sollte, ist die Verwendung der Standardmethode für einen polymodalen Vektor. Der Modus einer einfachen Folge von Zahlen wie 1,2,3,4 ist eigentlich alle diese Zahlen in der Folge, so dass sich "Modi" für ähnliche Folgen wie erwartet verhalten. zB modeave (c (1,2,3,4), method = "mode") gibt [1] 1 2 3 4 zurück. Unabhängig davon wäre ich sehr daran interessiert, die Funktion zu optimieren, da sie ziemlich ressourcenintensiv ist aktueller Zustand
Chris
Eine effizientere Version dieser Funktion finden Sie in @ hugovdbergs Beitrag oben :)
Chris
10

Hier eine andere Lösung:

freq <- tapply(mySamples,mySamples,length)
#or freq <- table(mySamples)
as.numeric(names(freq)[which.max(freq)])
teucer
quelle
Sie können die erste Zeile durch eine Tabelle ersetzen.
Jonathan Chang
Ich dachte, dass 'tapply' effizienter ist als 'table', aber beide verwenden eine for-Schleife. Ich denke, die Lösung mit Tabelle ist gleichwertig. Ich aktualisiere die Antwort.
Teucer
9

Ich kann noch nicht abstimmen, aber Rasmus Bååths Antwort ist genau das, wonach ich gesucht habe. Ich würde es jedoch ein wenig modifizieren, um die Verteilung beispielsweise für Werte nur zwischen 0 und 1 einzuschränken.

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

Wir sind uns bewusst, dass Sie Ihre Verteilung möglicherweise nicht einschränken möchten, und setzen Sie dann von = - "BIG NUMBER" auf = "BIG NUMBER".

AleRuete
quelle
error in density.default(x, from = from, to = to) : need at least 2 points to select a bandwidth automatically
Sergio
x sollte ein Vektor sein
AleRuete
8

Eine kleine Änderung an Ken Williams 'Antwort, die optionale Parameter na.rmund return_multiple.

Im Gegensatz zu den Antworten, auf die names()sich diese Antwort stützt , behält diese Antwort den Datentyp xder zurückgegebenen Werte bei.

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

Um zu zeigen, dass es mit den optionalen Parametern funktioniert und den Datentyp beibehält:

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"

Vielen Dank an @Frank für die Vereinfachung.

C8H10N4O2
quelle
7

Ich habe den folgenden Code geschrieben, um den Modus zu generieren.

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

Lass es uns versuchen:

MODE(mtcars)
MODE(CO2)
MODE(ToothGrowth)
MODE(InsectSprays)
Tyler Rinker
quelle
6

Basierend auf der Funktion von @ Chris zur Berechnung des Modus oder verwandter Metriken, jedoch unter Verwendung der Methode von Ken Williams zur Berechnung der Frequenzen. Dieser bietet eine Lösung für den Fall, dass überhaupt keine Modi vorhanden sind (alle Elemente gleich häufig) und einige besser lesbare methodNamen.

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

Da die Methode zur Berechnung der Frequenzen nach Ken verwendet wird, wird auch die Leistung optimiert. Mit dem Beitrag von AkselA habe ich einige der vorherigen Antworten verglichen, um zu zeigen, wie nahe meine Funktion an der Leistung von Ken liegt, wobei die Bedingungen für die verschiedenen Ausgangsoptionen nur einen geringen Overhead verursachen: Vergleich der Modusfunktionen

Hugovdberg
quelle
Der von Ihnen präsentierte Code scheint eine mehr oder weniger direkte Kopie der Modeim pracmaPaket enthaltenen Funktion zu sein. Möchtest du das erklären?
AkselA
"Ja wirklich?" Anscheinend bin ich nicht der einzige, der glaubt, dass dies ein guter Weg ist, um den Modus zu berechnen, aber ich wusste das ehrlich gesagt nicht (kannte dieses Paket noch nie zuvor). Ich habe Chris 'Funktion bereinigt und verbessert, indem ich Kens Version genutzt habe. Wenn sie dem Code eines anderen ähnelt, ist das rein zufällig.
Hugovdberg
Ich habe es mir gerade angesehen, aber auf welche Version des pracmaPakets beziehen Sie sich? Version 1.9.3 hat, soweit ich sehen kann, eine völlig andere Implementierung.
Hugovdberg
2
Schöne Änderung der Funktion. Nach einiger weiterer Lektüre bin ich zu dem Schluss gekommen, dass es keinen Konsens darüber gibt, ob einheitliche oder monofrequente Verteilungen Knoten haben. Einige Quellen sagen, dass die Liste der Modi die Verteilungen selbst sind, andere, dass es keinen Knoten gibt. Die einzige Übereinstimmung besteht darin, dass die Erstellung einer Liste von Modi für solche Distributionen weder sehr informativ noch besonders aussagekräftig ist. Wenn Sie möchten, dass die obige Funktion in solchen Fällen Modi erzeugt, entfernen Sie die Zeile: nmodes <- ifelse (nmodes == n, 0L, nmodes)
Chris
1
@greendiod sorry, ich habe deinen Kommentar verpasst. Es ist über diese Liste verfügbar: gist.github.com/Hugovdberg/0f00444d46efd99ed27bbe227bdc4d37
hugovdberg
6

Dieser Hack sollte gut funktionieren. Gibt Ihnen den Wert sowie die Anzahl der Modi:

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

R hat so viele Add-On-Pakete, dass einige von ihnen möglicherweise den [statistischen] Modus einer numerischen Liste / Serie / eines Vektors bereitstellen.

Die Standardbibliothek von R selbst scheint jedoch keine solche eingebaute Methode zu haben! Eine Möglichkeit, dies zu umgehen, besteht darin, ein Konstrukt wie das folgende zu verwenden (und dies in eine Funktion umzuwandeln, wenn Sie es häufig verwenden ...):

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

Für eine größere Beispielliste sollte eine temporäre Variable für den Maximalwert (tabSmpl) verwendet werden (ich weiß nicht, dass R dies automatisch optimieren würde).

Referenz: siehe "Wie wäre es mit Median und Modus?" in dieser KickStarting R-Lektion
Dies scheint zu bestätigen, dass (zumindest zum Zeitpunkt des Schreibens dieser Lektion) in R keine Modusfunktion vorhanden ist (nun ... mode (), wie Sie herausgefunden haben, wird zum Aktivieren des Variablentyps verwendet ).

mjv
quelle
3

Das funktioniert ganz gut

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

Hier ist eine Funktion, um den Modus zu finden:

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)
}
Ernest S Kirubakaran
quelle
3

Unten ist der Code, mit dem der Modus einer Vektorvariablen in R ermittelt werden kann.

a <- table([vector])

names(a[a==max(a)])
GauravS
quelle
3

Für diese gibt es mehrere Lösungen. Ich habe den ersten überprüft und danach meinen eigenen geschrieben. Poste es hier, wenn es jemandem hilft:

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

Testen wir es anhand einiger Beispiele. Ich nehme den irisDatensatz. Testet mit numerischen Daten

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

was Sie überprüfen können, ist korrekt.

Jetzt hat das einzige nicht numerische Feld im Iris-Datensatz (Species) keinen Modus. Lassen Sie uns mit unserem eigenen Beispiel testen

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

BEARBEITEN

Wie in den Kommentaren erwähnt, möchte der Benutzer möglicherweise den Eingabetyp beibehalten. In diesem Fall kann die Modusfunktion geändert werden in:

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

Die letzte Zeile der Funktion erzwingt einfach den endgültigen Moduswert zum Typ der ursprünglichen Eingabe.

Abhiroop Sarkar
quelle
Dies gibt einen Faktor zurück, während der Benutzer wahrscheinlich den Typ der Eingabe beibehalten möchte. Vielleicht einen mittleren Schritt hinzufügeny[,1] <- sort(unique(x))
Frank
2

Ich würde die Dichte () -Funktion verwenden, um ein geglättetes Maximum einer (möglicherweise kontinuierlichen) Verteilung zu identifizieren:

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

Dabei ist x die Datenerfassung. Achten Sie auf den Einstellparameter der Dichtefunktion, der die Glättung reguliert.

Yo B.
quelle
2

Während ich Ken Williams einfache Funktion mag, möchte ich die verschiedenen Modi abrufen, wenn sie existieren. In diesem Sinne verwende ich die folgende Funktion, die eine Liste der Modi zurückgibt, wenn mehrere oder einzelne.

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)) )]
} 
RandallShanePhD
quelle
Es wäre konsistenter für den programmatischen Gebrauch, wenn es immer eine Liste zurückgeben würde - von Länge 1, wenn es nur einen Modus gibt
asac
Das ist ein gültiger Punkt @ Antoine-Sac. Was mir an dieser Lösung gefällt, ist, dass der zurückgegebene Vektor die Antworten leicht adressierbar macht. Adressieren Sie einfach den Ausgang der Funktion: r <- Modus (c (2, 2, 3, 3)) mit den bei r [1] und r [2] verfügbaren Modi. Trotzdem machst du einen guten Punkt !!
RandallShanePhD
Genau hier ist Ihre Lösung unzureichend. Wenn modeeine Liste mit mehreren Werten zurückgegeben wird, ist r [1] nicht der erste Wert. Es ist stattdessen eine Liste der Länge 1, die den ersten Wert enthält, und Sie müssen r [[1]] ausführen, um den ersten Modus als numerische und nicht als Liste zu erhalten. Wenn es einen einzelnen Modus gibt, ist Ihr r keine Liste, daher funktioniert r [1], weshalb ich dachte, es sei inkonsistent. Aber da r [[1]] auch funktioniert, wenn r ein einfacher Vektor ist, gibt es tatsächlich eine Konsistenz, die ich nicht erkannt hatte, dass Sie immer [[auf Elemente zugreifen können.
Asac
2

Ich habe all diese Optionen durchgesehen und mich über ihre relativen Merkmale und Leistungen gewundert, also habe ich einige Tests durchgeführt. Falls jemand anderes neugierig ist, teile ich meine Ergebnisse hier.

Da ich mich nicht um alle hier veröffentlichten Funktionen kümmern wollte, konzentrierte ich mich auf ein Beispiel, das auf einigen Kriterien beruhte: Die Funktion sollte sowohl mit Zeichen-, Faktor-, logischen als auch numerischen Vektoren arbeiten, mit NAs und anderen problematischen Werten angemessen umgehen. und die Ausgabe sollte "vernünftig" sein, dh keine Zahlen als Zeichen oder andere solche Dummheiten.

Ich habe auch eine eigene Funktion hinzugefügt, die auf der gleichen rleIdee wie die von chrispy basiert, außer für eine allgemeinere Verwendung angepasst:

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

Am Ende habe ich fünf Funktionen auf zwei Testdatensätzen ausgeführt microbenchmark. Die Funktionsnamen beziehen sich auf die jeweiligen Autoren:

Geben Sie hier die Bildbeschreibung ein

Chris 'Funktion war auf method="modes"und eingestelltna.rm=TRUE standardmäßig , um sie vergleichbarer zu machen. Ansonsten wurden die Funktionen so verwendet, wie sie hier von ihren Autoren vorgestellt wurden.

Allein in Bezug auf die Geschwindigkeit gewinnt die Kens-Version problemlos, aber es ist auch die einzige, die nur einen Modus meldet, egal wie viele es tatsächlich gibt. Wie so oft gibt es einen Kompromiss zwischen Geschwindigkeit und Vielseitigkeit. In method="mode"Chris 'Version wird ein Wert zurückgegeben, wenn es einen Modus gibt, andernfalls NA. Ich denke, das ist eine nette Geste. Ich finde es auch interessant, wie einige Funktionen von einer erhöhten Anzahl eindeutiger Werte beeinflusst werden, während andere bei weitem nicht so stark sind. Ich habe den Code nicht im Detail studiert, um herauszufinden, warum das so ist, abgesehen davon, dass logisch / numerisch als Ursache beseitigt wurde.

AkselA
quelle
2

Der Modus kann nicht in allen Situationen nützlich sein. Die Funktion sollte sich also mit dieser Situation befassen. Versuchen Sie die folgende Funktion.

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

Ausgabe,

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."
Jibin
quelle
Entschuldigung, ich sehe nur nicht, wie dies etwas Neues zu dem hinzufügt, was bereits gepostet wurde. Außerdem scheint Ihre Ausgabe nicht mit Ihrer obigen Funktion übereinzustimmen.
not2qubit
2

Dies baut auf der Antwort von jprockbelly auf, indem eine Beschleunigung für sehr kurze Vektoren hinzugefügt wird. Dies ist nützlich, wenn Sie den Modus auf einen Datenrahmen anwenden oder mit vielen kleinen Gruppen datierbar sind:

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)))]
}
Dan Houghton
quelle
1

Eine andere einfache Option, die alle nach Häufigkeit geordneten Werte angibt, ist die Verwendung von rle:

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

Eine andere mögliche Lösung:

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

Verwendungszweck:

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

Ausgabe:

   user  system elapsed 
   0.32    0.00    0.31 
Naimish Agarwal
quelle
1

I Fall Ihre Beobachtungen sind Klassen von Reelle Zahlen und Sie erwarten , dass der Modus 2.5 sein , wenn Sie Ihre Beobachtungen sind 2, 2, 3 und 3 , dann können Sie den Modus schätzen mit mode = l1 + i * (f1-f0) / (2f1 - f0 - f2)dem l1 ..lower Grenze der häufigsten Klasse, f1 . Häufigkeit der häufigsten Klasse, f0 Häufigkeit der Klassen vor der häufigsten Klasse, f2 Häufigkeit der Klassen nach der häufigsten Klasse und i .. Klassenintervall wie z. B. 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

Wenn Sie das häufigste Level möchten und mehr als ein häufigstes Level haben, können Sie alle erhalten, z. B.:

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

Hinzufügen eines möglichen data.table-Ansatzes

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)}]
chinsoon12
quelle
1

Hier sind verschiedene Möglichkeiten, wie Sie dies in Theta (N) -Laufzeit tun können

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))
Paul Sartre
quelle
0

Könnte die folgende Funktion versuchen:

  1. numerische Werte in Faktor umwandeln
  2. Verwenden Sie summary (), um die Häufigkeitstabelle zu erhalten
  3. Rückgabemodus Der Index, dessen Frequenz am größten ist
  4. Transformationsfaktor zurück in numerisch, auch wenn es mehr als 1 Modus gibt, funktioniert diese Funktion gut!
mode <- function(x){
  y <- as.factor(x)
  freq <- summary(y)
  mode <- names(freq)[freq[names(freq)] == max(freq)]
  as.numeric(mode)
}
Wei
quelle
0

Der Berechnungsmodus ist meistens im Fall einer Faktorvariablen, die wir verwenden können

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

HouseVotes84 ist ein Datensatz, der im Paket 'mlbench' verfügbar ist.

Es wird der maximale Etikettenwert angegeben. Es ist einfacher, die eingebauten Funktionen selbst ohne Schreibfunktion zu verwenden.

Ashutosh Agrahari
quelle
0

Es scheint mir, dass wenn eine Sammlung einen Modus hat, ihre Elemente eins zu eins mit den natürlichen Zahlen abgebildet werden können. Das Problem des Findens des Modus reduziert sich also darauf, eine solche Zuordnung zu erstellen, den Modus der zugeordneten Werte zu finden und dann wieder auf einige der Elemente in der Sammlung abzubilden. (Der Umgang mit NAerfolgt in der Mapping-Phase).

Ich habe eine histogramFunktion, die nach einem ähnlichen Prinzip arbeitet. (Die speziellen Funktionen und Operatoren, die in dem hier vorgestellten Code verwendet werden, sollten in Shapiro und / oder in ordentlichem OveRse definiert werden . Die hier duplizierten Teile von Shapiro und ordentlichOveRse werden mit Genehmigung dupliziert. Die duplizierten Schnipsel können unter den Bedingungen dieser Website verwendet werden. ) R Pseudocode für histogramist

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

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

(Die speziellen binären Operatoren führen Piping , Currying und Komposition durch. ) Ich habe auch eine maxlocFunktion, die ähnlich ist which.max, aber alle absoluten Maxima eines Vektors zurückgibt . R Pseudocode für maxlocist

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

Dann

imode <- histogram %O% maxloc

und

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

berechnet den Modus jeder Sammlung, vorausgesetzt, die entsprechenden Funktionen map-ping und unmap-ping sind definiert.

Ana Nimbus
quelle