是否有用于查找模式的内置功能?

Nic*_*ick 370 statistics r r-faq

在R中,mean()median()是标准函数,可以满足您的期望. mode()告诉您对象的内部存储模式,而不是其参数中出现最多的值.但是有一个标准的库函数来实现向量(或列表)的统计模式吗?

Ken*_*ams 374

还有一个解决方案,适用于数字和字符/因子数据:

Mode <- function(x) {
  ux <- unique(x)
  ux[which.max(tabulate(match(x, ux)))]
}
Run Code Online (Sandbox Code Playgroud)

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

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

Modes <- function(x) {
  ux <- unique(x)
  tab <- tabulate(match(x, ux))
  ux[tab == max(tab)]
}
Run Code Online (Sandbox Code Playgroud)

  • 在多模态数据集的情况下,这不会返回所有模式(例如`c(1,1,2,2)`).你应该改变你的最后一行:`tab < - tabulate(match(x,ux)); ux [tab == max(tab)]` (37认同)
  • 也适用于逻辑!保留所有类型向量的数据类型(与其他答案中的某些实现不同). (7认同)
  • @verybadatthis为此,你将'ux [which.max(tabulate(match(x,ux)))]`替换为'max(tabulate(match(x,ux)))`. (6认同)
  • 你注意到`Mode(1:3)`给`1`和`Mode(3:1)`给'3`,所以Mode返回最频繁的元素,如果所有元素都是唯一的,则返回第一个元素. (4认同)
  • 正如Enrique所说:当没有模式时,此操作将失败,而是给您以* first *值为模式的印象。如果返回“ 0”或在“ NA”的情况下会好得多。 (2认同)

Geo*_*tas 64

存在一种包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")
Run Code Online (Sandbox Code Playgroud)

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

  • 所以要获得模式值,`mfv(mySamples)[1]`."1"很重要,因为它实际上返回了最常见的值*s*. (7认同)
  • @atomicules:使用 [1] 你只能得到第一种模式。对于双峰或一般 n 峰分布,您只需要 `mfv(mySamples)` (2认同)

Dan*_*Dan 57

在r邮件列表中找到了这个,希望它有用.这也是我的想法.你需要table()数据,排序然后选择第一个名字.它是hackish但应该工作.

names(sort(-table(x)))[1]
Run Code Online (Sandbox Code Playgroud)

  • 这也是一个聪明的工作.它有一些缺点:排序算法可能比基于max()的方法更节省空间和时间(=>对于更大的样本列表要避免).输出也是模式(原谅双关语/歧义)"字符"而不是"数字".当然,测试多模态分布的需要通常需要存储已排序的表以避免重新处理它. (6认同)
  • 我用 1e6 个元素的因子测量了运行时间,这个解决方案比公认的答案快了几乎 3 倍! (2认同)

jpr*_*lly 45

我发现肯·威廉姆斯在上面的帖子很棒,我添加了几行来解释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)))])
}
Run Code Online (Sandbox Code Playgroud)


Ras*_*åth 30

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

estimate_mode <- function(x) {
  d <- density(x)
  d$x[which.max(d$y)]
}
Run Code Online (Sandbox Code Playgroud)

然后得到模式估计:

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
Run Code Online (Sandbox Code Playgroud)

  • 只需注意这一点:您可以通过这种方式获得任何一组连续数字的"模式".数据不需要来自正常分布即可工作.以下是从统一分布中获取数字的示例.`set.seed(1); 一个<-runif(100); 模式<-density的(a)$ X [which.max(密度的(a)$ Y)]; abline(V =模式)` (3认同)

Chr*_*ris 14

以下功能有三种形式:

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

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()
}
Run Code Online (Sandbox Code Playgroud)


teu*_*cer 10

这里,另一个解决方案

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


Seb*_*ian 10

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

library(collapse)
fmode(x, g = NULL, w = NULL, ...)
Run Code Online (Sandbox Code Playgroud)

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


Ale*_*ete 9

我还不能投票,但RasmusBåå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)]
}
Run Code Online (Sandbox Code Playgroud)

我们知道您可能不想限制所有发行版,然后从= - "BIG NUMBER"设置为="BIG NUMBER"


C8H*_*4O2 8

肯威廉姆斯答案的一个小修改,添加了可选的参数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])
}
Run Code Online (Sandbox Code Playgroud)

要显示它与可选参数一起使用并维护数据类型:

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"
Run Code Online (Sandbox Code Playgroud)

感谢@Frank的简化.


Tyl*_*ker 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)))
}
Run Code Online (Sandbox Code Playgroud)

我们来试试吧:

MODE(mtcars)
MODE(CO2)
MODE(ToothGrowth)
MODE(InsectSprays)
Run Code Online (Sandbox Code Playgroud)


hug*_*erg 6

基于@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'")
}
Run Code Online (Sandbox Code Playgroud)

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

  • 对功能的修改很好.在进一步阅读之后,我得出的结论是,关于统一或单频分布是否有节点没有达成共识,一些消息来源说模式列表是分布本身,另一些则认为没有节点.唯一的一致意见是,为这种分布制作一个模式列表既不是非常有用,也不是特别有意义.如果您希望上述函数生成这种情况的模式,则删除行:nmodes < - ifelse(nmodes == n,0L,nmodes) (2认同)

小智 6

这个hack应该可以正常工作.给你价值以及模式的数量:

Mode <- function(x){
a = table(x) # x is a vector
return(a[which.max(a)])
}
Run Code Online (Sandbox Code Playgroud)


Dan*_*ton 5

这是建立在 jprocckbelly 的答案的基础上的,通过增加非常短的向量的速度。当将模式应用于具有许多小组的 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)))]
}
Run Code Online (Sandbox Code Playgroud)