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)?
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)]
}
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
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]
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)))])
}
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
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()
}
Ici, une autre solution:
freq <- tapply(mySamples,mySamples,length)
#or freq <- table(mySamples)
as.numeric(names(freq)[which.max(freq)])
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"
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.
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)
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)])
}
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.
Cela fonctionne très bien
> a<-c(1,1,2,2,3,3,4,4,5)
> names(table(a))[table(a)==max(table(a))]
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).
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)
}
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."
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)])
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:
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.
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
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.
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)) )]
}
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
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)
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.
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)
où 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"
Pourrait essayer la fonction suivante:
mode <- function(x){
y <- as.factor(x)
freq <- summary(y)
mode <- names(freq)[freq[names(freq)] == max(freq)]
as.numeric(mode)
}
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.
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)))]
}