459

在 R 中,mean()并且median()是执行您所期望的标准功能。 mode()告诉你对象的内部存储模式,而不是在其参数中出现最多的值。但是是否有一个标准库函数可以实现向量(或列表)的统计模式?

4

36 回答 36

464

另一种解决方案,适用于数字和字符/因子数据:

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

在我的极小机器上,它可以在大约半秒内生成并找到一个 10M 整数向量的模式。

如果您的数据集可能有多种模式,则上述解决方案采用与 相同的方法which.max,并返回模式集的第一个出现值。要返回所有模式,请使用此变体(来自评论中的 @digEmAll):

Modes <- function(x) {
  ux <- unique(x)
  tab <- tabulate(match(x, ux))
  ux[tab == max(tab)]
}
于 2011-11-18T21:33:10.687 回答
73

有一个包modeest提供单变量单峰(有时是多峰)数据模式的估计器和通常概率分布的模式值。

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

有关更多信息,请参阅此页面

于 2010-03-30T19:05:46.073 回答
68

在 r 邮件列表中找到了这个,希望对您有所帮助。反正我也是这么想的。您需要 table() 数据,排序然后选择名字。这是hackish,但应该工作。

names(sort(-table(x)))[1]
于 2010-03-30T18:19:29.960 回答
58

我发现上面的 Ken Williams 帖子很棒,我添加了几行来说明 NA 值,并使其成为一个易于使用的函数。

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)))])
}
于 2014-09-03T03:21:55.960 回答
42

估计您认为来自连续单变量分布(例如正态分布)的数字向量的模式的一种快速而肮脏的方法是定义和使用以下函数:

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

然后得到模式估计:

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
于 2012-12-14T08:00:22.177 回答
14

以下函数有三种形式:

method = "mode" [默认]:计算单峰向量的模式,否则返回 NA
method = "nmodes":计算向量中的模式数
method = "modes":列出单峰或多峰的所有模式向量

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()
}
于 2013-03-25T17:21:23.240 回答
11

在这里,另一个解决方案:

freq <- tapply(mySamples,mySamples,length)
#or freq <- table(mySamples)
as.numeric(names(freq)[which.max(freq)])
于 2010-03-30T20:21:29.403 回答
9

我还不能投票,但 Rasmus Bååth 的答案正是我想要的。但是,我会对其进行一些修改,以允许限制分布,例如仅在 0 和 1 之间的值。

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

我们知道您可能不想限制所有分布,然后设置 from=-"BIG NUMBER", to="BIG NUMBER"

于 2013-09-12T11:50:04.897 回答
9

对 Ken Williams 的回答进行了小修改,添加了可选参数na.rmreturn_multiple.

与依赖的答案不同,此答案在返回值中names()维护 的数据类型。x

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

为了显示它与可选参数一起工作并维护数据类型:

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"

感谢@Frank 的简化。

于 2017-07-20T13:43:38.150 回答
7

为了生成模式,我编写了以下代码。

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

让我们尝试一下:

MODE(mtcars)
MODE(CO2)
MODE(ToothGrowth)
MODE(InsectSprays)
于 2011-11-18T04:41:03.643 回答
7

基于@Chris 的函数来计算模式或相关指标,但是使用 Ken Williams 的方法来计算频率。这为根本没有模式(所有元素同样频繁)和一些更易读的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'")
}

由于它使用 Ken 的方法来计算频率,因此性能也得到了优化,我使用 AkselA 的帖子对之前的一些答案进行了基准测试,以显示我的函数在性能上如何接近 Ken,各种输出选项的条件仅导致较小的开销: 模式功能比较

于 2016-06-29T11:05:33.713 回答
6

这个黑客应该可以正常工作。为您提供模式的值和计数:

Mode <- function(x){
a = table(x) # x is a vector
return(a[which.max(a)])
}
于 2016-09-13T07:01:34.463 回答
4

fmode现在在 CRAN 上可用的包中的通用函数collapse实现了基于索引散列的基于 C++ 的模式。它比上述任何一种方法都要快得多。它带有向量、矩阵、data.frames 和 dplyr 分组小标题的方法。句法:

libary(collapse)
fmode(x, g = NULL, w = NULL, ...)

其中x可以是上述对象之一,g提供可选的分组向量或分组向量列表(用于分组模式计算,也在 C++ 中执行),并且w(可选)提供数字权重向量。在分组的 tibble 方法中,没有g参数,你可以做data %>% group_by(idvar) %>% fmode.

于 2020-03-19T21:45:11.423 回答
3

R 有如此多的附加包,其中一些很可能提供数字列表/系列/向量的 [统计] 模式。

但是 R 本身的标准库似乎没有这样的内置方法!解决此问题的一种方法是使用如下构造(如果您经常使用,则将其转换为函数......):

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

对于更大的样本列表,应该考虑为 max(tabSmpl) 值使用一个临时变量(我不知道 R 会自动优化这个)

参考:见“中位数和众数怎么样?” 在这个KickStarting R 课程
中 这似乎证实了(至少在编写本课时)R 中没有模式函数(嗯...... mode() 你发现它用于断言变量的类型)。

于 2010-03-30T18:25:50.147 回答
3

这工作得很好

> a<-c(1,1,2,2,3,3,4,4,5)
> names(table(a))[table(a)==max(table(a))]
于 2014-02-07T04:16:37.170 回答
3

这是一个查找模式的函数:

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)
}
于 2015-09-06T09:09:18.273 回答
3

下面是可用于在 R 中查找向量变量模式的代码。

a <- table([vector])

names(a[a==max(a)])
于 2017-02-21T10:58:20.513 回答
3

为此提供了多种解决方案。我检查了第一个,然后写了我自己的。如果对任何人有帮助,请在此处发布:

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

让我们用几个例子来测试它。我正在获取iris数据集。让我们用数字数据进行测试

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

您可以验证它是正确的。

现在虹膜数据集(物种)中唯一的非数字字段没有模式。让我们用我们自己的例子来测试

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

编辑

如评论中所述,用户可能希望保留输入类型。在这种情况下,模式函数可以修改为:

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

该函数的最后一行只是将最终模式值强制转换为原始输入的类型。

于 2018-04-24T12:43:15.257 回答
2

给出按频率排序的所有值的另一个简单选项是使用rle

df = as.data.frame(unclass(rle(sort(mySamples))))
df = df[order(-df$lengths),]
head(df)
于 2012-12-04T14:29:14.487 回答
2

我会使用 density() 函数来识别(可能是连续的)分布的平滑最大值:

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

其中 x 是数据集合。注意调节平滑的密度函数的调节参数。

于 2014-05-02T10:03:41.453 回答
2

虽然我喜欢 Ken Williams 的简单功能,但我想检索多个模式(如果存在)。考虑到这一点,我使用以下函数返回模式列表(如果是多个模式或单一模式)。

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)) )]
} 
于 2014-12-24T16:08:02.960 回答
2

我浏览了所有这些选项并开始想知道它们的相关特性和性能,所以我做了一些测试。如果其他人对此感到好奇,我将在这里分享我的结果。

不想打扰这里发布的所有函数,我选择关注基于几个标准的示例:该函数应该适用于字符、因子、逻辑和数字向量,它应该适当地处理 NA 和其他有问题的值,并且输出应该是“明智的”,即没有数字作为字符或其他类似的愚蠢。

我还添加了我自己的功能,它基于与rlechrispy 相同的想法,但适用于更一般的用途:

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

我最终在两组测试数据上运行了五个函数,通过microbenchmark. 函数名称指的是它们各自的作者:

在此处输入图像描述

Chris 的函数method="modes"默认na.rm=TRUE设置为使其更具可比性,但除此之外,这些函数由其作者在此处提供。

仅就速度而言,Kens 版本轻松获胜,但它也是其中唯一一款只会报告一种模式的版本,无论真正有多少。通常情况下,需要在速度和多功能性之间进行权衡。在method="mode"中,如果存在一种模式,则 Chris 的版​​本将返回一个值,否则返回 NA。我认为这是一个很好的接触。我还认为有趣的是,一些函数如何受到唯一值数量增加的影响,而其他函数则几乎没有。除了消除逻辑/数字作为原因之外,我还没有详细研究代码以找出原因。

于 2016-05-27T02:49:33.367 回答
2

模式并非在所有情况下都有用。所以函数应该解决这种情况。试试下面的功能。

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

输出,

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."
于 2018-09-05T10:09:12.057 回答
2

这建立在 jprockbelly 的答案之上,通过为非常短的向量添加加速。这在将模式应用于具有大量小组的 data.frame 或数据表时很有用:

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)))]
}
于 2018-11-13T22:56:55.640 回答
1

另一种可能的解决方案:

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

用法:

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

输出:

   user  system elapsed 
   0.32    0.00    0.31 
于 2015-12-16T02:45:39.433 回答
1

我的情况是,您的观察结果是来自实数的类,并且当您的观察结果为2、2、3和 3 时,您希望众数为 2.5,然后您可以使用where l1 ..最常见类的下限f1来估计众数。 .频率最频繁类,f0 ..最频繁类之前的类频率,f2 ..最频繁类之后的类频率和i ..间隔,如在1、2、3给出mode = l1 + i * (f1-f0) / (2f1 - f0 - f2)

#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

如果您想要最频繁的级别并且您有多个最频繁的级别,您可以获取所有这些级别,例如:

x <- c(2,2,3,5,5)
names(which(max(table(x))==table(x)))
#"2" "5"
于 2019-03-26T11:46:23.583 回答
1

如果你问 R 中的内置函数,也许你可以在 package 上找到它pracma。在那个包里面,有一个函数叫做 Mode.

于 2020-07-29T20:26:28.833 回答
0

可以尝试以下功能:

  1. 将数值转换为因子
  2. 使用 summary() 获取频率表
  3. return mode 频率最大的索引
  4. 即使有超过 1 种模式,也可以将转换因子转换回数字,这个功能很好用!
mode <- function(x){
  y <- as.factor(x)
  freq <- summary(y)
  mode <- names(freq)[freq[names(freq)] == max(freq)]
  as.numeric(mode)
}
于 2014-04-05T07:36:49.603 回答
0

计算模式主要是在因子变量的情况下,然后我们可以使用

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

HouseVotes84 是“mlbench”包中可用的数据集。

它将给出最大标签值。内置函数本身更容易使用,无需编写函数。

于 2016-09-21T19:15:01.770 回答
0

在我看来,如果一个集合有一个模式,那么它的元素可以与自然数一对一地映射。因此,找到模式的问题简化为生成这样的映射,找到映射值的模式,然后映射回集合中的某些项目。(处理NA发生在映射阶段)。

我有一个histogram在类似主体上运行的函数。(此处提供的代码中使用的特殊功能和运算符应在Shapiro和/或netOveRse中定义。此处复制的 Shapiro 和 NeatOveRse 部分经许可如此复制;复制的片段可根据本网站的条款使用。 ) R代码histogram

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

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

(特殊的二元运算符完成管道柯里化和合成)我还有一个maxloc函数,它类似于which.max,但返回向量的所有绝对最大值。R代码maxloc

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

然后

imode <- histogram %O% maxloc

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

将计算任何集合的模式,前提是定义了适当的map-ping 和unmap-ping 函数。

于 2019-10-30T23:47:06.640 回答
0

raster::modal()作为选项添加,但请注意,这raster是一个庞大的软件包,如果您不进行地理空间工作,可能不值得安装。

可以从https://github.com/rspatial/raster/blob/master/src/modal.cpphttps://github.com/rspatial/raster/blob/master/R/modal 中提取源代码。 R变成了个人 R 包,适合那些特别热衷的人。

于 2019-11-15T06:58:57.420 回答
0

这是我的 data.table 解决方案,它返回完整表的逐行模式。我用它来推断行类。它负责 data.table 中新的 set() 函数,并且应该非常快。虽然它不管理 NA,但可以通过查看此页面上的众多其他解决方案来添加。

majorityVote <- function(mat_classes) {
  #mat_classes = dt.pour.centroids_num
  dt.modes <- data.table(mode = integer(nrow(mat_classes)))
  for (i in 1:nrow(mat_classes)) {
    cur.row <- mat_classes[i]
    cur.mode <- which.max(table(t(cur.row)))
    set(dt.modes, i=i, j="mode", value = cur.mode)
  }

  return(dt.modes)
}

可能的用法:

newClass <- majorityVote(my.dt)  # just a new vector with all the modes
于 2021-02-08T14:22:57.450 回答
-1

抱歉,我可能把它想得太简单了,但这不是工作吗?(我的机器上的 1E6 值需要 1.3 秒):

t0 <- Sys.time()
summary(as.factor(round(rnorm(1e6), 2)))[1]
Sys.time()-t0

你只需要用你的向量替换“round(rnorm(1e6),2)”。

于 2013-04-10T14:33:52.757 回答
-1

您还可以计算一个实例在您的集合中发生的次数并找到最大次数。例如

> temp <- table(as.vector(x))
> names (temp)[temp==max(temp)]
[1] "1"
> as.data.frame(table(x))
r5050 Freq
1     0   13
2     1   15
3     2    6
> 
于 2013-12-03T19:16:38.670 回答
-2

以下是您可以在 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))
于 2020-03-31T03:44:06.687 回答
-3

计算包含离散值的向量“v”的 MODE 的一种简单方法是:

names(sort(table(v)))[length(sort(table(v)))]
于 2016-08-27T07:54:50.617 回答