web-dev-qa-db-fra.com

Existe-t-il une fonction intégrée pour trouver le mode?

Dans R, mean() et median() sont des fonctions standard qui font ce que vous attendez. mode() vous indique le mode de stockage interne de l'objet, pas la valeur qui survient le plus dans son argument. Mais existe-t-il une fonction de bibliothèque standard qui implémente le mode statistique pour un vecteur (ou une liste)?

339
Nick

Une solution supplémentaire, qui fonctionne à la fois pour les données numériques et caractères/facteurs:

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

Sur ma petite machine, cela peut générer et trouver le mode d’un vecteur de 10 millions d’entiers en une demi-seconde environ.

Si votre ensemble de données peut avoir plusieurs modes, la solution ci-dessus adopte la même approche que which.max et renvoie la valeur apparaissant en premier de l'ensemble de modes. Pour retourner les modes all , utilisez cette variante (à partir de @digEmAll dans les commentaires):

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

Il existe un paquetage modeest qui fournit des estimateurs du mode des données unimodales univariées (et parfois multimodales) et des valeurs des modes des distributions de probabilité usuelles.

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

Pour plus d'informations, voir cette page

60
George Dontas

trouvé ceci sur la liste de diffusion, espérons que cela vous sera utile. C'est aussi ce que je pensais quand même. Vous aurez envie de table () les données, de trier puis de choisir le prénom. C'est bidouille mais devrait fonctionner.

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

J'ai trouvé le post de Ken Williams excellent, j'ai ajouté quelques lignes pour rendre compte des valeurs de NA et en faire une fonction facilitant. 

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

Un moyen rapide et aléatoire d’estimer le mode d’un vecteur de nombres provenant d’une distribution continue univariée (par exemple une distribution normale) consiste à définir et à utiliser la fonction suivante:

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

Ensuite, pour obtenir l'estimation du mode:

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

La fonction suivante se présente sous trois formes:

method = "mode" [défaut]: calcule le mode pour un vecteur unimodal, sinon renvoie un NA
method = "nmodes": calcule le nombre de modes dans le vecteur
method = "modes": liste tous les modes pour un vecteur unimodal ou polymodal

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

Ici, une autre solution:

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

Je ne peux pas encore voter mais la réponse de Rasmus Bååth est ce que je cherchais. Cependant, je le modifierais un peu, ce qui permettrait de contrôler la distribution, par exemple, pour des valeurs comprises entre 0 et 1. 

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

Nous sommes conscients que vous ne souhaitez peut-être pas restreindre votre distribution, puis définissez-la entre = - "BIG NUMBER", et = = "BIG NUMBER"

9
AleRuete

Une petite modification à la réponse de Ken Williams, en ajoutant les paramètres optionnels na.rm et return_multiple.

Contrairement aux réponses qui reposent sur names(), cette réponse conserve le type de données x dans la ou les valeurs renvoyées.

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

Pour montrer cela fonctionne avec les paramètres facultatifs et maintient le type de données:

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"

Merci à @Frank pour la simplification.

7
C8H10N4O2

J'ai écrit le code suivant afin de générer le mode.

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

Essayons:

MODE(mtcars)
MODE(CO2)
MODE(ToothGrowth)
MODE(InsectSprays)
7
Tyler Rinker

Ce hack devrait bien fonctionner. Vous donne la valeur ainsi que le nombre de mode: 

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

Basé sur la fonction de @ Chris pour calculer le mode ou les mesures connexes, utilisez toutefois la méthode de Ken Williams pour calculer les fréquences. Celui-ci fournit une solution pour le cas d'aucun mode (tous les éléments sont également fréquents), et quelques noms plus lisibles method

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

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

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

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

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

Puisqu'il utilise la méthode de Ken pour calculer les fréquences, les performances sont également optimisées. À l'aide de l'article d'AkselA, j'ai comparé certaines des réponses précédentes afin de montrer comment ma fonction est proche de celle de Ken en termes de performances.  Comparison of Mode functions

5
hugovdberg

Cela fonctionne très bien

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

R a tellement de paquetages complémentaires que certains d’entre eux peuvent très bien fournir le mode [statistique] d’une liste/série/vecteur numérique.

Cependant, la bibliothèque standard de R elle-même ne semble pas avoir une telle méthode intégrée! Une façon de contourner ce problème consiste à utiliser une structure similaire à celle-ci (et à transformer cette fonction en une fonction si vous utilisez souvent ...):

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

Pour une plus grande liste d’échantillons, on devrait envisager d’utiliser une variable temporaire pour la valeur max (tabSmpl) (je ne sais pas si R l’optimiserait automatiquement)

Référence: voir "Et la médiane et le mode?" dans cette KickStarting R lesson
Cela semble confirmer que (du moins au moment de l'écriture de cette leçon) il n'y a pas de fonction de mode dans R (bon ... le mode () que vous avez découvert est utilisé pour affirmer le type de variables).

3
mjv

Voici une fonction pour trouver le mode:

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

Le mode ne peut pas être utile dans toutes les situations. Donc, la fonction devrait remédier à cette situation. Essayez la fonction suivante.

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

Sortie,

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

Vous trouverez ci-dessous le code qui peut être utilisé pour trouver le mode d’une variable vectorielle dans R.

a <- table([vector])

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

Je parcourais toutes ces options et commençais à me poser des questions sur leurs caractéristiques et leurs performances. J'ai donc fait quelques tests. Au cas où d'autres personnes seraient curieuses de connaître la même chose, je partage mes résultats ici.

Ne voulant pas s’occuper de toutes les fonctions postées ici, j’ai choisi de me concentrer sur un échantillon basé sur quelques critères: la fonction devrait fonctionner à la fois sur les vecteurs caractère, facteur, logique et numérique, elle devrait traiter les AN et autres valeurs problématiques de manière appropriée, et le résultat doit être "raisonnable", c'est-à-dire sans chiffres comme caractère ou autre sottise.

J'ai également ajouté une fonction personnelle, basée sur la même idée rle que celle de chrispy's, à l'exception de son adaptation à une utilisation plus générale:

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

J'ai fini par exécuter cinq fonctions, sur deux ensembles de données de test, via microbenchmark. Les noms de fonctions font référence à leurs auteurs respectifs:

 enter image description here

La fonction de Chris a été définie par défaut sur method="modes" et na.rm=TRUE pour la rendre plus comparable, mais à part cela, les fonctions ont été utilisées telles que présentées ici par leurs auteurs.

En termes de vitesse seulement, la version Kens gagne facilement, mais c’est aussi la seule de ces versions qui n’indiquera qu’un seul mode, peu importe le nombre. Comme souvent, il existe un compromis entre vitesse et polyvalence. Dans method="mode", la version de Chris renverra une valeur si et seulement s'il y a un mode, sinon NA. Je pense que c'est une bonne idée ... Je pense aussi qu'il est intéressant de voir comment certaines fonctions sont affectées par un nombre croissant de valeurs uniques, alors que d'autres ne le sont pas autant. Je n'ai pas étudié le code en détail pour comprendre pourquoi, mis à part l'élimination de logique/numérique comme cause.

2
AkselA

Plusieurs solutions sont proposées pour celui-ci. J'ai vérifié le premier et ensuite écrit le mien. Publiez-le ici si cela aide quelqu'un:

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

Permet de tester avec quelques exemples. Je prends le jeu de données iris. Permet de tester avec des données numériques

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

que vous pouvez vérifier est correct.

Désormais, le seul champ non numérique de l'ensemble de données iris (Espèce) n'a pas de mode. Testons avec notre propre exemple

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

MODIFIER

Comme mentionné dans les commentaires, l'utilisateur peut vouloir conserver le type d'entrée. Dans ce cas, la fonction mode peut être modifiée pour:

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

La dernière ligne de la fonction convertit simplement la valeur du mode final en fonction du type de l'entrée d'origine.

2
Abhiroop Sarkar

Bien que j'aime la fonction simple de Ken Williams, j'aimerais récupérer les multiples modes s'ils existent. En gardant cela à l’esprit, j’utilise la fonction suivante qui renvoie une liste des modes multiples ou uniques.

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

Une autre solution possible:

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

Usage:

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

Sortie:

   user  system elapsed 
   0.32    0.00    0.31 
1
Naimish Agarwal

Une autre option simple donnant toutes les valeurs ordonnées par fréquence consiste à utiliser rle:

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

J'utiliserais la fonction de densité () pour identifier un maximum lissé d'une distribution (éventuellement continue):

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

où x est la collecte de données. Faites attention au ajuster paremeter de la fonction de densité qui régule le lissage.

1
Yo B.

Dans le cas où vos observations sont classes de nombres réels et vous vous attendez à ce que le mode soit égal à 2,5 lorsque vos observations sont 2, 2, 3 et 3, puis vous pouvez estimer le mode avec mode = l1 + i * (f1-f0) / (2f1 - f0 - f2) l1 .. limite inférieure de la classe la plus fréquente, f1 .. fréquence de la classe la plus fréquente, f0 .. fréquence des classes précédant le plus classe fréquente, f2 .. fréquence des classes après classe la plus fréquente et i .. Intervalle de classe tel que donné, par exemple dans 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

Si vous voulez le niveau le plus fréquent et que vous avez plus d’un niveau le plus fréquent, vous pouvez tous les obtenir, par exemple. avec:

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

Pourrait essayer la fonction suivante:

  1. transformer des valeurs numériques en facteur
  2. utilisez summary () pour obtenir le tableau de fréquences
  3. retourne l'index dont la fréquence est la plus grande
  4. transformer le facteur en numérique même s'il y a plus d'un mode, cette fonction fonctionne bien!
mode <- function(x){
  y <- as.factor(x)
  freq <- summary(y)
  mode <- names(freq)[freq[names(freq)] == max(freq)]
  as.numeric(mode)
}
0
Wei

Mode de calcul est principalement en cas de facteur variable alors nous pouvons utiliser 

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

HouseVotes84 est un jeu de données disponible dans le package 'mlbench'.

cela donnera la valeur maximum de l'étiquette. il est plus facile d'utiliser les fonctions incorporées elles-mêmes sans écrire de fonction.

0
Ashutosh Agrahari

Cela s'appuie sur la réponse de jprockbelly, en ajoutant une vitesse plus rapide pour les vecteurs très courts. Ceci est utile lorsque vous appliquez le mode à un fichier data.frame ou datatable avec beaucoup de petits groupes:

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