代码之家  ›  专栏  ›  技术社区  ›  Nick

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

  •  343
  • Nick  · 技术社区  · 14 年前

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

    29 回复  |  直到 6 年前
        1
  •  347
  •   Ken Williams Dirk is no longer here    6 年前

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

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

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

    如果您的数据集可能有多个模式,那么上述解决方案采用的方法与 which.max ,并返回 首次出现 模式集的值。归来 全部的 模式,使用此变量(来自注释中的@digemall):

    Modes <- function(x) {
      ux <- unique(x)
      tab <- tabulate(match(x, ux))
      ux[tab == max(tab)]
    }
    
        2
  •  60
  •   Yorgos    14 年前

    有包裹 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")
    

    有关详细信息,请参阅 this page

        3
  •  53
  •   Dan    14 年前

    在R邮件列表中找到了这个,希望有帮助。不管怎样,这也是我的想法。您需要对数据进行table(),排序,然后选择名字。这是一种黑客行为,但应该有效。

    names(sort(-table(x)))[1]
    
        4
  •  42
  •   Gregor Thomas    9 年前

    我发现上面的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)))])
    }
    
        5
  •  28
  •   Rasmus Bååth    12 年前

    一种快速而肮脏的方法来估算你认为来自连续单变量分布(如正态分布)的数字矢量的模式,它定义并使用以下函数:

    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
    
        6
  •  13
  •   Chris    9 年前

    以下功能有三种形式:

    method=“mode”[默认值]:计算单模向量的模式,否则返回na
    method=“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()
    }
    
        7
  •  10
  •   teucer    14 年前

    这里,另一个解决方案:

    freq <- tapply(mySamples,mySamples,length)
    #or freq <- table(mySamples)
    as.numeric(names(freq)[which.max(freq)])
    
        8
  •  9
  •   AleRuete    11 年前

    我还不能投票,但拉斯穆斯的回答是我正在寻找的。 但是,我会稍微修改它,允许反向分布,例如,对于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)]
    }
    

    我们知道您可能不想约束所有的分布,然后将从=-“大数字”设置为“大数字”

        9
  •  7
  •   d-cubed Tyler Rinker    11 年前

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

    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)
    
        10
  •  7
  •   C8H10N4O2    7 年前

    对Ken Williams的答案做了小修改,添加了可选参数 na.rm return_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的简化。

        11
  •  6
  •   Nsquare    8 年前

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

    Mode <- function(x){
    a = table(x) # x is a vector
    return(a[which.max(a)])
    }
    
        12
  •  5
  •   hugovdberg    8 年前

    基于@chris的函数来计算模式或相关度量,但是使用ken williams的方法来计算频率。这一个解决方案可以解决根本没有模式的情况(所有元素都同样频繁),以及一些可读性更强的 method name。

    模式<-功能(x,method=“one”,na.rm=false){
    X<-取消列表(X)
    如果(n.rm){
    x& lt;-x[!是NA(x)
    }
    
    #获取唯一值
    UX<-唯一(X)
    N<-长度(UX)
    
    #获取所有唯一值的频率
    频率表(匹配(x,ux)
    模式<-频率==max(频率)
    
    #确定模式数
    nmodes<-和(模式)
    nmodes<-ifelse(nmodes==n,0l,nmodes)
    
    if(方法%在%c中(“one”,“mode”,“)是.na(方法))。{
    #如果不是一种模式,返回NA,否则返回该模式
    如果(NMODE!= 1){
    返回(NA)
    }否则{
    返回(UX[哪个(模式)]
    }
    }else if(方法%在%c中(“n”,“nmodes”)){
    #返回模式数
    返回(nMODE)
    }else if(方法%c(“all”,“modes”)){
    #如果不存在模式,返回NA,否则返回所有模式
    如果(nmodes>0){
    返回(UX[哪个(模式)]
    }否则{
    返回(不适用)
    }
    }
    警告(“警告:方法无法识别。有效的方法是'one'/'mode'[默认值]、'n'/'n modes'和'all'/'modes')
    }
    < /代码> 
    
    

    由于它使用ken的方法来计算频率,所以性能也得到了优化,使用Aksela的post i对之前的一些答案进行了基准测试,以显示我的函数在性能上如何接近ken的函数,各种输出选项的条件只会导致很小的开销:

    对于完全没有模式的情况(所有元素都同样频繁),以及一些更可读的情况提供了修复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的post i对之前的一些答案进行了基准测试,以显示我的函数在性能上如何接近ken的函数,各种输出选项的条件只会导致很小的开销: Comparison of Mode functions

        13
  •  3
  •   mjv    14 年前

    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 lesson
    这似乎证实了(至少在本课的写作中)R中没有模式函数(好吧…所发现的mode()用于断言变量的类型)。

        14
  •  3
  •   statistic1979    11 年前

    这个很好用

    > a<-c(1,1,2,2,3,3,4,4,5)
    > names(table(a))[table(a)==max(table(a))]
    
        15
  •  3
  •   Ernest S Kirubakaran    9 年前

    以下是查找模式的函数:

    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)
    }
    
        16
  •  2
  •   RandallShanePhD    10 年前

    虽然我喜欢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)) )]
    } 
    
        17
  •  2
  •   AkselA    8 年前

    我查看了所有这些选项,开始怀疑它们的相对特性和性能,所以我做了一些测试。如果其他人对此感兴趣,我将在这里分享我的结果。

    我不想为这里发布的所有函数操心,而是选择了一个基于以下几个标准的示例:函数应该同时处理字符、因子、逻辑和数字向量,它应该适当地处理NAS和其他有问题的值,并且输出应该是“合理的”,即没有数字作为字符或其他类似的sillineSS/

    我还添加了一个我自己的函数,它基于与Chrispy的相同的 rle idea,除了适合更一般的使用:

    库(magrittr)
    
    AKSEL<-函数(x,freq=false){
    Z & lt;- 2
    如果(频率)z<-1:2
    运行<-x%>%as.vector%>%sort%>%rle%>%unclass%>%data.frame
    colnames(run)<-c(“freq”,“value”)。
    运行[which(运行$freq==max(运行$freq)),z]%>%as.vector
    }
    
    设定种子(2)
    
    F<-样本(C(“是”,“否”,“可能”,NA),10,替换=真)%>%因子
    Aksel(F)
    
    (1)也许是
    
    C<-样本(C(“Steve”,“Jane”,“Jonas”,“Petra”),20,替换=真)
    AKSEL(C,频率=真)
    
    αFRQ值
    史提夫7
    < /代码> 
    
    

    最后,我通过micronchmark在两组测试数据上运行了五个函数。函数名引用各自的作者:

    Chris'Function was set tomethod=“modes”andna.rm=trueby default to make it more comparable,but other than the functions were used as presented here by their authors.

    单就速度而言,kens版赢的很容易,但这也是唯一一个只报告一种模式的模式,不管有多少个。通常情况下,速度和多功能性之间存在着权衡。在method=“mode”中,chris'version将返回一个值iff there is one mode,else na.我觉得这是一个很好的接触。 我还认为有趣的是,一些函数是如何受到越来越多的唯一值的影响的,而其他函数则没有那么多。除了消除逻辑/数字原因之外,我没有详细研究代码来找出原因。

    对此很好奇,我在这里分享我的结果。

    我不想为这里发布的所有函数操心,而是选择了一个基于以下几个标准的示例:函数应该同时处理字符、因子、逻辑和数字向量,它应该适当地处理NAS和其他有问题的值,并且输出应该是“合理的”,即没有数字作为字符或其他类似的愚蠢。

    我还添加了一个我自己的函数,它基于相同的rle作为克里斯比的想法,除了适用于更广泛的用途:

    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. 函数名指的是各自的作者:

    enter image description here

    Chris的功能设置为method="modes"na.rm=TRUE默认情况下,为了使其更具可比性,除此之外,它们的作者在这里介绍了函数。

    单就速度而言,kens版赢的很容易,但这也是唯一一个只报告一种模式的模式,不管有多少个。通常情况下,速度和多功能性之间存在着权衡。在method="mode",chris的版本将返回一个值,如果存在一个模式,则返回na。我觉得这是一个很好的接触。 我还认为有趣的是,一些函数是如何受到越来越多的唯一值的影响的,而其他函数则没有那么多。除了排除逻辑/数字原因之外,我没有详细研究代码来找出原因。

        18
  •  2
  •   David Arenburg Ulrik    7 年前

    下面的代码可以用来找到R中向量变量的模式。

    a <- table([vector])
    
    names(a[a==max(a)])
    
        19
  •  2
  •   Abhiroop Sarkar    6 年前

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

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

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

        20
  •  2
  •   Jibin    6 年前

    模式不能在任何情况下都有用。所以函数应该处理这种情况。尝试以下功能。

    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."
    
        21
  •  1
  •   Alice Purcell    12 年前

    另一个简单的选项是使用 rle :

    df = as.data.frame(unclass(rle(sort(mySamples))))
    df = df[order(-df$lengths),]
    head(df)
    
        22
  •  1
  •   Yollanda Beetroot    10 年前

    我将使用密度()函数来确定(可能是连续的)分布的平滑最大值:

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

    其中x是数据收集。注意 调整 用于调节平滑度的密度函数的参数。

        23
  •  1
  •   Naimish Agarwal    9 年前

    另一个可能的解决方案:

    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 
    
        24
  •  0
  •   hrbrmstr    10 年前

    可以尝试以下功能:

    1. 将数值转换为因子
    2. 使用summary()获取频率表
    3. 返回模式频率最大的索引
    4. 转换因子返回到数字,即使有超过1个模式,这个功能工作得很好!
    mode <- function(x){
      y <- as.factor(x)
      freq <- summary(y)
      mode <- names(freq)[freq[names(freq)] == max(freq)]
      as.numeric(mode)
    }
    
        25
  •  0
  •   David Arenburg Ulrik    7 年前

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

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

    HouseVotes84是“MLBench”软件包中提供的数据集。

    它将给出最大标签值。在不编写函数的情况下,内置函数本身更容易使用。

        26
  •  0
  •   Dan Houghton    6 年前

    这建立在jprockbell的答案基础上,通过增加极短向量的速度。这在将模式应用于包含大量小组的data.frame或datatable时非常有用:

    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)))]
    }
    
        27
  •  -1
  •   Kami    11 年前

    对不起,我可能觉得太简单了,但这不是工作吗?(对于我的机器上的1E6值,以1.3秒为单位):

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

    你只需要用向量替换“圆形(RNORM(1E6),2)”。

        28
  •  -1
  •   girl    11 年前

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

    > 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
    > 
    
        29
  •  -3
  •   C8H10N4O2    7 年前

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

    names(sort(table(v)))[length(sort(table(v)))]