442 votes

Comment trouver le mode statistique ?

En R, mean() et median() sont des fonctions standard qui font ce que l'on attend d'elles. mode() vous indique le mode de stockage interne de l'objet, et non la valeur qui apparaît le plus souvent dans son argument. Mais existe-t-il une fonction de la bibliothèque standard qui implémente le mode statistique pour un vecteur (ou une liste) ?

4 votes

Vous devez préciser si vos données sont des entiers, des numériques, des facteurs... ? L'estimation du mode pour les données numériques sera différente, et utilise des intervalles. Voir le plus moderne

8 votes

Pourquoi R ne dispose-t-il pas d'une fonction intégrée pour le mode ? Pourquoi R considère-t-il mode pour être la même que la fonction class ?

445voto

Ken Williams Points 4686

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

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

Sur ma toute petite machine, cela peut générer et trouver le mode d'un vecteur de 10M 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 démarche que which.max et renvoie le première apparition valeur de l'ensemble des modes. Pour retourner tous modes, utilisez cette variante (de @digEmAll dans les commentaires) :

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

7 votes

Fonctionne aussi pour les logiques ! Préserve le type de données pour tous les types de vecteurs (contrairement à certaines implémentations dans d'autres réponses).

43 votes

Cela ne renvoie pas tous les modes dans le cas d'un ensemble de données multimodales (par ex. c(1,1,2,2) ). Vous devriez changer votre dernière ligne par : tab <- tabulate(match(x, ux)); ux[tab == max(tab)]

1 votes

Comment pourrais-je modifier ceci pour retourner le nombre de fois que la valeur modale se produit ? Par exemple, pour c(1,1,1,2,2) il retournerait 3 .

72voto

George Dontas Points 12116

Il y a un paquet modeest qui fournissent des estimateurs du mode des données univariées unimodales (et parfois multimodales) et des valeurs des modes des distributions de probabilité habituelles.

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

8 votes

Donc, pour obtenir juste la valeur du mode, mfv(mySamples)[1] . Le site 1 étant important car il renvoie en fait la valeur la plus fréquente s .

0 votes

Cela ne semble pas fonctionner dans cet exemple : library(modeest) a <- rnorm( 50, 30, 2 ) b <- rnorm( 100, 35, 2 ) c <- rnorm( 20, 37, 2 ) temperatureºC <- c( a, b, c ) hist(temperatureºC) #mean abline(v=mean(temperatureºC), col="red",lwd=2) #median abline(v=median(temperatureºC),col="black",lwd=2) #mode abline(v=mlv(temperatureºC, method = "mfv")[1],col="orange",lwd=2)

1 votes

@atomicules : avec [1] vous n'obtenez que le premier mode. Pour une distribution bimodale ou une distribution générale n-modale, il vous faudrait juste mfv(mySamples)

64voto

Dan Points 1680

J'ai trouvé ceci sur la liste de diffusion r, j'espère que c'est utile. C'est aussi ce que je pensais de toute façon. Vous devrez utiliser la fonction table() pour trier les données, puis choisir le premier nom. C'est un peu bricolé mais ça devrait marcher.

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

6 votes

C'est aussi une solution intelligente. Elle présente quelques inconvénients : l'algorithme de tri peut être plus gourmand en espace et en temps que les approches basées sur max() (=> à éviter pour les listes d'échantillons plus grandes). De plus, la sortie est de mode (pardonnez le jeu de mots/ambiguïté) "caractère" et non "numérique". Et, bien sûr, le besoin de tester la distribution multimodale nécessiterait typiquement le stockage de la table triée pour éviter de la traiter à nouveau.

2 votes

J'ai mesuré le temps d'exécution avec un facteur de 1e6 éléments et cette solution était plus rapide que la réponse acceptée par presque un facteur 3 !

0 votes

Je viens de le convertir en nombre en utilisant as.numeric(). Cela fonctionne parfaitement bien. Merci !

40voto

Rasmus Bååth Points 627

Une façon rapide et pratique d'estimer le mode d'un vecteur de nombres que vous pensez provenir d'une distribution univariée continue (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

3 votes

Juste une remarque à ce sujet : vous pouvez obtenir un "mode" de n'importe quel groupe de nombres continus de cette manière. Les données n'ont pas besoin de provenir d'une distribution normale pour fonctionner. Voici un exemple avec des nombres issus d'une distribution uniforme. set.seed(1); a<-runif(100); mode<-density(a)$x[which.max(density(a)$y)]; abline(v=mode)

0 votes

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

0 votes

@xhie Ce message d'erreur vous dit tout ce que vous devez savoir. Si vous n'avez qu'un seul point, vous devez définir la bande passante manuellement en appelant density . Cependant, si vous n'avez qu'un seul point de données, la valeur de ce point de données sera probablement votre meilleure estimation du mode de toute façon...

11voto

teucer Points 1877

Ici, une autre solution :

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

0 votes

Vous pouvez remplacer la première ligne par le tableau.

0 votes

Je pensais que 'tapply' était plus efficace que 'table', mais ils utilisent tous deux une boucle for. Je pense que la solution avec table est équivalente. Je mets à jour la réponse.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X