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

392

En R, mean()et median()sont des fonctions standards qui font ce que vous attendez. mode()vous indique le mode de stockage interne de l'objet, pas la valeur qui apparaît 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)?

pseudo
la source
4
Vous devez préciser si vos données sont entières, numériques, factorielles ...? L'estimation de mode pour les valeurs numériques sera différente et utilise des intervalles. Voir modeest
smci
2
Pourquoi R n'a-t-il pas de fonction intégrée pour le mode? Pourquoi R considère-t- modeil la même chose que la fonction class?
Corey Levinson

Réponses:

400

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

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

Sur ma petite machine dinky, cela peut générer et trouver le mode d'un vecteur entier de 10M en environ une demi-seconde.

Si votre ensemble de données peut avoir plusieurs modes, la solution ci-dessus adopte la même approche que which.maxet renvoie la première valeur apparente de l'ensemble de modes. Pour retourner tous les modes, utilisez cette variante (de @digEmAll dans les commentaires):

Modes <- function(x) {
  ux <- unique(x)
  tab <- tabulate(match(x, ux))
  ux[tab == max(tab)]
}
Ken Williams
la source
7
Fonctionne également 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).
DavidC
39
Cela ne renvoie pas tous les modes en cas de jeu de données multimodal (par exemple c(1,1,2,2)). Vous devriez changer votre dernière ligne avec:tab <- tabulate(match(x, ux)); ux[tab == max(tab)]
digEmAll
6
@verybadatthis Pour cela, vous devez remplacer ux[which.max(tabulate(match(x, ux)))]par juste max(tabulate(match(x, ux))).
Ken Williams
4
Vous notez que Mode(1:3)donne 1et Mode(3:1)donne 3, donc Mode renvoie l'élément le plus fréquent ou le premier si tous sont uniques.
Enrique Pérez Herrero
2
Comme Enrique l'a dit: cela échoue quand il n'y a pas de mode et vous donne plutôt l'impression que la première valeur est le mode. Cela aurait été bien mieux s'il revenait 0ou NAdans ces cas.
not2qubit
66

Il existe un ensemble modeestqui fournit des estimateurs du mode des données unimarié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

George Dontas
la source
7
Donc , pour obtenir juste la valeur de mode, mfv(mySamples)[1]. L' 1être important car il renvoie en fait la valeur la plus fréquente s .
atomicules
cela ne semble pas fonctionner dans cet exemple: bibliothèque (modeest) a <- rnorm (50, 30, 2) b <- rnorm (100, 35, 2) c <- rnorm (20, 37, 2) temperatureºC <- c (a, b, c) hist (températureºC) # moyenne abline (v = moyenne (températureºC), col = "rouge", lwd = 2) #médiane abline (v = médiane (températureºC), col = "noir", lwd = 2) #mode abline (v = mlv (temperatureºC, méthode = "mfv") [1], col = "orange", lwd = 2)
Agus camacho
1
@atomicules: avec [1] vous obtenez seulement le premier mode. Pour une distribution bimodale ou n-modale générale, il vous suffirait demfv(mySamples)
petzi
1
Pour R version 3.6.0, il indique que la fonction 'n'a pas pu trouver la fonction "mlv"' et la même erreur lorsque j'ai essayé mfv (mysamples). Est-il déprécié?
Dr Nisha Arora du
@DrNishaArora: Avez-vous téléchargé le package 'modeest'?
Petzi
59

trouvé cela 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 voudrez déposer () les données, trier puis choisir le prénom. C'est hackish mais ça devrait marcher.

names(sort(-table(x)))[1]
Dan
la source
6
C'est aussi un travail intelligent. Il présente quelques inconvénients: l'algorithme de tri peut prendre plus de temps et d'espace que les approches basées sur max () (=> à éviter pour les plus grandes listes d'échantillons). La sortie est également de mode (pardonnez le jeu de mots / ambiguïté) "caractère" et non "numérique". Et, bien sûr, la nécessité de tester la distribution multimodale nécessiterait généralement le stockage de la table triée pour éviter de la resserrer.
mjv
2
J'ai mesuré le temps de course avec un facteur de 1e6 éléments et cette solution était plus rapide que la réponse acceptée de presque 3!
vonjd
Je viens de le convertir en nombre en utilisant as.numeric (). Fonctionne parfaitement bien. Je vous remercie!
Abhishek Singh
47

J'ai trouvé que le post de Ken Williams ci-dessus était génial, j'ai ajouté quelques lignes pour tenir compte des valeurs NA et en ai fait une fonction pour plus de 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)))])
}
jprockbelly
la source
J'ai trouvé quelques accélérations à ce sujet, voir la réponse ci-dessous.
Dan Houghton
33

Une manière rapide et sale d'estimer le mode d'un vecteur de nombres que vous croyez 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
Rasmus Bååth
la source
3
Juste une note sur celui-ci: vous pouvez obtenir un "mode" de n'importe quel groupe de nombres continus de cette façon. Les données n'ont pas besoin de provenir d'une distribution normale pour fonctionner. Voici un exemple prenant des nombres d'une distribution uniforme. 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 Ce message d'erreur vous indique tout ce que vous devez savoir. Si vous n'avez qu'un seul point, vous devez définir la bande passante manuellement lors de l'appel 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 pour le mode de toute façon ...
Rasmus Bååth
Vous avez raison, mais j'ai ajouté juste un tweak: estimate_mode <- function(x) { if (length(x)>1){ d <- density(x) d$x[which.max(d$y)] }else{ x } } je teste la méthode pour estimer le vent de direction prédominante, au lieu de la moyenne de la direction en utilisant la moyenne vectorielle avec un package circulaire. I ', en travaillant avec des points sur une pente polygonale, il y a donc parfois un seul point avec une direction. Merci!
Sergio
@xhie Cela semble raisonnable :)
Rasmus Bååth
14

La fonction suivante se présente sous trois formes:

method = "mode" [default]: calcule le mode pour un vecteur unimodal, sinon renvoie une
méthode NA = "nmodes": calcule le nombre de modes dans le vecteur
method = "modes": répertorie tous les modes pour un unimodal ou polymodal vecteur

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
la source
Dans votre description de ces fonctions, vous avez échangé "modes" et "nmodes". Voir le code. En fait, "nmodes" renvoie un vecteur de valeurs et "modes" renvoie un nombre de modes. Néanmoins, votre fonction est la meilleure âme pour trouver les modes que j'ai vus jusqu'à présent.
Grzegorz Adam Kowalski
Merci beaucoup pour le commentaire. "nmode" et "modes" devraient maintenant se comporter comme prévu.
Chris
Votre fonction fonctionne presque, sauf lorsque chaque valeur apparaît aussi souvent en utilisant method = 'modes'. Ensuite, la fonction renvoie toutes les valeurs uniques, mais en réalité il n'y a pas de mode, elle devrait donc retourner à la NAplace. J'ajouterai une autre réponse contenant une version légèrement optimisée de votre fonction, merci pour l'inspiration!
hugovdberg
Le seul moment où un vecteur numérique non vide doit normalement générer un NA avec cette fonction est lors de l'utilisation de la méthode par défaut sur un vecteur polymodal. Le mode d'une simple séquence de nombres tels que 1,2,3,4 est en fait tous ces nombres dans la séquence, donc pour des séquences similaires, les "modes" se comportent comme prévu. par exemple modeave (c (1,2,3,4), method = "modes") renvoie [1] 1 2 3 4 Indépendamment de cela, je serais très intéressé de voir la fonction optimisée car elle est assez gourmande en ressources dans son état actuel
Chris
Pour une version plus efficace de cette fonction, voir le post de @ hugovdberg ci-dessus :)
Chris
10

Ici, une autre solution:

freq <- tapply(mySamples,mySamples,length)
#or freq <- table(mySamples)
as.numeric(names(freq)[which.max(freq)])
teucer
la source
Vous pouvez remplacer la première ligne par table.
Jonathan Chang
Je pensais que «tapply» est plus efficace que «table», mais ils utilisent tous les deux une boucle for. Je pense que la solution avec table est équivalente. Je mets à jour la réponse.
teucer
9

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 en permettant de limiter la distribution par exemple pour les valeurs uniquement 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 savons que vous ne voudrez peut-être pas du tout limiter votre distribution, puis définissez de = - "BIG NUMBER" à = "BIG NUMBER"

AleRuete
la source
error in density.default(x, from = from, to = to) : need at least 2 points to select a bandwidth automatically
Sergio
x devrait être un vecteur
AleRuete
8

Une petite modification à la réponse de Ken Williams, ajoutant des paramètres optionnels na.rmet return_multiple.

Contrairement aux réponses reposant sur names(), cette réponse conserve le type de données de xdans 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 qu'il 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.

C8H10N4O2
la source
7

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)
Tyler Rinker
la source
6

Basé sur la fonction de @ Chris pour calculer le mode ou les métriques associées, mais en utilisant la méthode de Ken Williams pour calculer les fréquences. Celui-ci fournit un correctif pour le cas d'aucun mode du tout (tous les éléments sont également fréquents), et quelques methodnoms plus lisibles .

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, en utilisant le post d'AkselA, j'ai comparé certaines des réponses précédentes pour montrer comment ma fonction est proche de celle de Ken en termes de performances, les conditions pour les différentes options de sortie ne provoquant que des frais généraux mineurs: Comparaison des fonctions de mode

hugovdberg
la source
Le code que vous présentez semble être une copie plus ou moins simple de la Modefonction trouvée dans le pracmapackage. Soin d'expliquer?
AkselA
Vraiment? Apparemment, je ne suis pas le seul à penser que c'est une bonne façon de calculer le mode, mais honnêtement, je ne le savais pas (je n'ai jamais connu ce package auparavant). J'ai nettoyé la fonction de Chris et l'ai améliorée en exploitant la version de Ken, et si elle ressemble au code de quelqu'un d'autre, c'est purement fortuit.
hugovdberg
Je l'ai étudié tout à l'heure, mais à quelle version du pracmapackage faites-vous référence? La version 1.9.3 a une implémentation complètement différente pour autant que je puisse voir.
hugovdberg
2
Joli amendement à la fonction. Après quelques lectures supplémentaires, je suis amené à la conclusion qu'il n'y a pas de consensus sur la question de savoir si les distributions uniformes ou monofréquences ont des nœuds, certaines sources disant que la liste des modes sont les distributions elles-mêmes, d'autres qu'il n'y a pas de nœud. Le seul accord est que la production d'une liste de modes pour de telles distributions n'est ni très informative ni particulièrement significative. SI vous souhaitez que la fonction ci-dessus produise des modes dans de tels cas, supprimez la ligne: nmodes <- ifelse (nmodes == n, 0L, nmodes)
Chris
1
@greendiod désolé, j'ai raté votre commentaire. Il est disponible via ce gist: gist.github.com/Hugovdberg/0f00444d46efd99ed27bbe227bdc4d37
hugovdberg
6

Ce hack devrait fonctionner correctement. Vous donne la valeur ainsi que le nombre de modes:

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

R a tellement de modules 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 cela est d'utiliser une construction comme celle-ci (et de la transformer en 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 liste d'échantillons plus grande, on devrait envisager d'utiliser une variable temporaire pour la valeur max (tabSmpl) (je ne sais pas si R optimiserait automatiquement cela)

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

mjv
la source
3

Cela fonctionne très bien

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

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

Voici le code qui peut être utilisé pour trouver le mode d'une variable vectorielle dans R.

a <- table([vector])

names(a[a==max(a)])
GauravS
la source
3

Il existe plusieurs solutions pour celle-ci. J'ai vérifié le premier et j'ai ensuite écrit le mien. L'afficher ici s'il aide quelqu'un:

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

Permet de le tester avec quelques exemples. Je prends l' irisensemble de données. 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 du jeu de données iris (Espèce) n'a pas de mode. Essayons avec notre propre exemple

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

ÉDITER

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 contraint simplement la valeur du mode final au type de l'entrée d'origine.

Abhiroop Sarkar
la source
Cela renvoie un facteur, tandis que l'utilisateur souhaite probablement conserver le type de l'entrée. Peut-être ajouter une étape intermédiairey[,1] <- sort(unique(x))
Frank
2

J'utiliserais la fonction 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 à l' ajuster paremeter de la fonction de densité qui régulent le lissage.

Yo B.
la source
2

Bien que j'aime la fonction simple de Ken Williams, j'aimerais récupérer les multiples modes s'ils existent. Dans cet esprit, j'utilise la fonction suivante qui renvoie une liste des modes s'ils sont 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)) )]
} 
RandallShanePhD
la source
Il serait plus cohérent pour une utilisation programmatique s'il
renvoyait
C'est un point valide @ antoine-sac. Ce que j'aime dans cette solution, c'est que le vecteur renvoyé laisse les réponses facilement adressables. Adressez simplement la sortie de la fonction: r <- mode (c (2, 2, 3, 3)) avec les modes disponibles à r [1] et r [2]. Pourtant, vous faites un bon point !!
RandallShanePhD
C'est précisément là que votre solution échoue. Si moderenvoie une liste avec plusieurs valeurs, alors r [1] n'est pas la première valeur; c'est plutôt une liste de longueur 1 contenant la première valeur et vous devez faire r [[1]] pour obtenir le premier mode sous forme numérique et non une liste. Maintenant, quand il y a un seul mode, votre r n'est pas une liste donc r [1] fonctionne, c'est pourquoi je pensais qu'il était incohérent. Mais puisque r [[1]] fonctionne également lorsque r est un simple vecteur, il y a en fait une cohérence que je n'avais pas réalisée en ce que vous pouvez toujours l'utiliser [[pour accéder aux éléments.
asac
2

Je regardais toutes ces options et j'ai commencé à m'interroger sur leurs caractéristiques et performances relatives, j'ai donc fait quelques tests. Au cas où quelqu'un d'autre serait curieux de savoir la même chose, je partage mes résultats ici.

Ne voulant pas se soucier de toutes les fonctions publié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 de caractère, de facteur, logiques et numériques, elle devrait traiter les NA et autres valeurs problématiques de manière appropriée, et la sortie doit être «sensible», c'est-à-dire pas de chiffres comme caractère ou autre idiotie.

J'ai également ajouté une fonction à moi, qui est basée sur la même rleidée que chrispy's, sauf adaptée pour 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 microbenchmark. Les noms de fonction font référence à leurs auteurs respectifs:

entrez la description de l'image ici

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

En ce qui concerne la vitesse seule, la version Kens gagne facilement, mais elle est également la seule de celles-ci à ne signaler qu'un seul mode, peu importe le nombre. Comme c'est souvent le cas, il y a un compromis entre vitesse et polyvalence. Dans method="mode", la version de Chris retournera une valeur si il n'y a qu'un mode, sinon NA. Je pense que c'est une belle touche. Je pense également qu'il est intéressant de voir comment certaines fonctions sont affectées par un nombre accru de valeurs uniques, tandis que d'autres ne le sont pas autant. Je n'ai pas étudié le code en détail pour comprendre pourquoi, à part éliminer la logique / numérique comme cause.

AkselA
la source
2

Le mode ne peut pas être utile dans toutes les situations. Donc, la fonction devrait répondre à 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)
}

Production,

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
la source
Désolé, je ne vois pas comment cela ajoute quelque chose de nouveau à ce qui a déjà été publié. De plus, votre sortie semble incompatible avec votre fonction ci-dessus.
not2qubit
2

Cela s'appuie sur la réponse de jprockbelly, en ajoutant une accélération pour les vecteurs très courts. Ceci est utile lors de l'application du mode à un data.frame ou à une table de données avec de nombreux 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)))]
}
Dan Houghton
la source
1

Une autre option simple qui donne toutes les valeurs classées par fréquence est d'utiliser rle:

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

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

Production:

   user  system elapsed 
   0.32    0.00    0.31 
Naimish Agarwal
la source
1

Si vos observations sont des classes de nombres réels et que vous vous attendez à ce que le mode soit de 2,5 lorsque vos observations sont 2, 2, 3 et 3, vous pouvez alors 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 avant la classe la plus fréquente, f2 .. fréquence des classes après la classe la plus fréquente et i .. intervalle de classe comme indiqué par exemple en 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 en avez plusieurs , vous pouvez tous les obtenir, par exemple avec:

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

Ajout d'une approche data.table possible

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
la source
1

Voici plusieurs façons de le faire en temps d'exécution Theta (N)

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
la source
0

Pourrait essayer la fonction suivante:

  1. transformer des valeurs numériques en facteur
  2. utilisez summary () pour obtenir le tableau des fréquences
  3. mode retour 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)
}
Wei
la source
0

Le mode de calcul est principalement en cas de variable de facteur, alors nous pouvons utiliser

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

HouseVotes84 est un ensemble de données disponible dans le package «mlbench».

il donnera la valeur maximale de l'étiquette. il est plus facile à utiliser par les fonctions intégrées elles-mêmes sans fonction d'écriture.

Ashutosh Agrahari
la source
0

Il me semble que si une collection a un mode, alors ses éléments peuvent être mappés un à un avec les nombres naturels. Ainsi, le problème de la recherche du mode se réduit à la production d'un tel mappage, à la recherche du mode des valeurs mappées, puis au mappage vers certains des éléments de la collection. (Le traitement NAse produit lors de la phase de cartographie).

J'ai une histogramfonction qui fonctionne sur un principe similaire. (Les fonctions et opérateurs spéciaux utilisés dans le code présenté ici doivent être définis dans Shapiro et / ou dans neatOveRse . Les parties de Shapiro et neatOveRse dupliquées ici sont ainsi dupliquées avec permission; les extraits de code dupliqués peuvent être utilisés selon les termes de ce site. ) R pseudocode pour histogramis

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

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

(Les opérateurs binaires spéciaux accomplissent la tuyauterie , le curry et la composition ) J'ai également une maxlocfonction, qui est similaire à which.max, mais renvoie tous les maxima absolus d'un vecteur. Pseudocode R pour maxlocis

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

alors

imode <- histogram %O% maxloc

et

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

calculera le mode de toute collection, à condition que les fonctions map-ping et unmap-ping appropriées soient définies.

Ana Nimbus
la source