it-swarm.com.de

Gibt es eine integrierte Funktion zum Auffinden des Modus?

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

339
Nick

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 Dinky-Maschine kann dies in etwa einer halben Sekunde den Modus eines 10M-Integer-Vektors erzeugen und finden.

Wenn Ihr Datensatz möglicherweise über mehrere Modi verfügt, verwendet die obige Lösung den gleichen Ansatz wie which.max und gibt den zuerst erscheinenden - Wert des Modi-Satzes zurück. Um alle -Modi zurückzugeben, verwenden Sie diese Variante (aus @digEmAll in den Kommentaren):

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

Es gibt ein Paket modeest, das Schätzer des Modus univariater unimodaler (und manchmal multimodaler) Daten und Werte der Modi gewöhnlicher Wahrscheinlichkeitsverteilungen liefert.

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

60
George Dontas

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

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

Ich fand den Artikel von Ken Williams oben toll, ich habe ein paar Zeilen hinzugefügt, um die NA-Werte zu berücksichtigen, und machte es zu einer Funktion für die Vereinfachung. 

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

Eine schnelle und schmutzige Methode zum Schätzen des Modus eines Zahlenvektors, von dem Sie glauben, dass er aus einer kontinuierlichen univariaten Verteilung stammt (z. B. einer Normalverteilung), besteht in der Definition und Verwendung folgender Funktion:

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

Dann erhalten Sie die Modusschätzung:

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
28
Rasmus Bååth

Die folgende Funktion gibt es in drei Formen:

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

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

Hier eine andere Lösung:

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

Ich kann noch nicht wählen, aber Rasmus Bååths Antwort ist das, wonach ich gesucht habe. .__ Ich würde es jedoch etwas modifizieren, um die Verteilung beispielsweise für Werte 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)]
}

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

9
AleRuete

Eine kleine Modifikation der Antwort von Ken Williams, wobei optional die Parameter na.rm und return_multiple hinzugefügt werden.

Im Gegensatz zu den Antworten, die sich auf names() verlassen, behält diese Antwort den Datentyp x in den zurückgegebenen Werten 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, wird der Datentyp beibehalten:

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"

Danke an @Frank für die Vereinfachung.

7
C8H10N4O2

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

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

Basierend auf der Funktion von @ Chris zur Berechnung des Modus oder der zugehörigen Metriken, jedoch mit der Methode von Ken Williams zur Berechnung der Frequenzen. Dieser enthält ein Update für den Fall, dass überhaupt keine Modi vorhanden sind (alle Elemente gleich häufig) und einige lesbare method-Namen. 

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 Ken-Methode zur Berechnung der Frequenzen mithilfe der Ken-Methode berechnet wird, wird die Leistung ebenfalls optimiert. Mit AkselAs Post-I-Benchmarking habe ich einige der vorherigen Antworten untersucht, um zu zeigen, wie meine Funktion der Leistung von Ken nahe kommt.  Comparison of Mode functions

5
hugovdberg

Das funktioniert ziemlich gut

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

R hat so viele Zusatzpakete, 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 integrierte Methode zu haben! Eine Möglichkeit, dies zu umgehen, besteht darin, ein Konstrukt wie das folgende zu verwenden (und diese Funktion bei häufiger Verwendung in eine Funktion umzuwandeln)

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 Stichprobenliste sollte die Verwendung einer temporären Variablen für den Wert max (tabSmpl) in Betracht gezogen werden (ich weiß nicht, dass R dies automatisch optimieren würde).

Referenz: siehe "Median und Modus" in dieser KickStarting R-Stunde
Dies scheint zu bestätigen, dass (zumindest zum Zeitpunkt des Schreibens dieser Lektion) keine Modusfunktion in R vorhanden ist (well ... mode (), wie Sie herausgefunden haben, wird der Typ der Variablen verwendet).

3
mjv

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

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."
2
Jibin

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

a <- table([vector])

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

Ich habe all diese Optionen durchgesehen und angefangen, mich über ihre jeweiligen Eigenschaften und Leistungen zu wundern. Deshalb habe ich einige Tests durchgeführt. Falls noch jemand neugierig ist, teile ich meine Ergebnisse hier mit.

Da ich mich nicht mit all den Funktionen beschäftigen möchte, die hier veröffentlicht werden, habe ich mich auf eine Stichprobe konzentriert, die auf wenigen Kriterien basiert: Die Funktion sollte sowohl auf Zeichen-, Faktor-, logischen und numerischen Vektoren funktionieren, als auch mit NAs und anderen problematischen Werten. und die Ausgabe sollte "sinnvoll" sein, dh keine numerischen Zeichen als Charakter oder andere derartige Dummheit.

Ich fügte auch eine eigene Funktion hinzu, die auf der gleichen rle-Idee basiert wie chrispy, mit Ausnahme der allgemeinen Verwendung:

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

Ich habe am Ende fünf Funktionen mit zwei Sätzen von Testdaten über microbenchmark ausgeführt. Die Funktionsnamen beziehen sich auf ihre jeweiligen Autoren:

 enter image description here

Chris 'Funktion wurde standardmäßig auf method="modes" und na.rm=TRUE gesetzt, um sie vergleichbarer zu machen, ansonsten wurden die Funktionen so verwendet, wie sie hier von ihren Autoren dargestellt wurden.

In Sachen Geschwindigkeit allein gewinnt die Kens-Version leicht, aber es ist auch die einzige, die nur einen Modus anzeigt, egal wie viele es wirklich gibt. Wie so oft gibt es einen Kompromiss zwischen Geschwindigkeit und Vielseitigkeit. In method="mode" gibt Chris 'Version einen Wert zurück, wenn es einen Modus gibt, andernfalls NA. Ich denke, das ist eine nette Geste ... __ Ich denke auch, dass es interessant ist, wie einige Funktionen von einer erhöhten Anzahl einzigartiger Werte beeinflusst werden, während andere bei weitem nicht so viel sind. Ich habe den Code nicht im Detail studiert, um herauszufinden, warum das so ist, abgesehen von der Beseitigung der logischen/numerischen Ursache.

2
AkselA

Hierfür gibt es mehrere Lösungen. Ich habe die erste überprüft und danach meine eigene geschrieben. Posten Sie es hier, wenn es jemandem hilft:

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

Lass es uns mit ein paar Beispielen testen. Ich nehme den iris-Datensatz. Lässt Test mit numerischen Daten

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

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

Das einzige nicht numerische Feld im Iris-Dataset (Species) hat jetzt keinen Modus. Testen wir es mit unserem eigenen Beispiel

> 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 folgendermaßen geändert werden:

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.

2
Abhiroop Sarkar

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

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

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 
1
Naimish Agarwal

Eine weitere 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)
1
Alice Purcell

Ich würde die density () - 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 Parameter adjust der Dichtefunktion, der die Glättung regelt.

1
Yo B.

Wenn Ihre Beobachtungen Klassen aus reellen Zahlen sind und Sie erwarten, dass der Modus 2,5 ist, wenn Ihre Beobachtungen 2, 2, 3 und 3 sind, dann könnten Sie schätzen der Modus mit mode = l1 + i * (f1-f0) / (2f1 - f0 - f2) wobei l1 .. Untergrenze der häufigsten Klasse, f1 .. Häufigkeit der häufigsten Klasse, f0 .. Häufigkeit der Klassen vor den meisten häufige Klasse, f2 .. Häufigkeit der Klassen nach der häufigsten Klasse und i .. Klassenintervall wie z 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 haben möchten und mehr als ein häufigstes Level haben, können Sie alle erhalten, z. mit:

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

Könnte die folgende Funktion versuchen:

  1. umwandlung von numerischen Werten in Faktor
  2. verwenden Sie summary (), um die Häufigkeitstabelle zu erhalten
  3. rückkehrmodus der Index, dessen Häufigkeit am größten ist
  4. wenn Sie mehr als einen Modus verwenden, 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)
}
0
Wei

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

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

HouseVotes84 ist ein Datensatz im mlbench-Paket.

es gibt den maximalen Labelwert. Es ist einfacher, die eingebauten Funktionen ohne Schreibfunktion zu verwenden.

0

Dies basiert auf der Antwort von jprockbelly, indem für sehr kurze Vektoren eine Beschleunigung hinzugefügt wird. Dies ist nützlich, wenn Sie den Modus auf einen data.frame anwenden oder mit vielen kleinen Gruppen datieren können:

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