【问题标题】:Equal frequency discretization in RR中的等频离散化
【发布时间】:2011-04-20 13:29:29
【问题描述】:

我无法在 R 中找到执行等频离散化的函数。我偶然发现了“infotheo”包,但经过一些测试后,我发现算法被破坏了。 CRAN 似乎不再支持“dprep”。

编辑:

为了清楚起见,我不需要在 bin 之间分隔值。我真的想要相同的频率,如果一个值最终出现在两个箱中并不重要。例如:

c(1,3,2,1,2,2) 

应该给一个箱子c(1,1,2)和一个c(2,2,3)

【问题讨论】:

  • 因为你的真正目标似乎有点混乱,我添加了一些例子。

标签: r


【解决方案1】:

编辑:鉴于你的真正目标,你为什么不做(更正):

 EqualFreq2 <- function(x,n){
    nx <- length(x)
    nrepl <- floor(nx/n)
    nplus <- sample(1:n,nx - nrepl*n)
    nrep <- rep(nrepl,n)
    nrep[nplus] <- nrepl+1
    x[order(x)] <- rep(seq.int(n),nrep)
    x
}

这将返回一个向量,其中包含它们所在的 bin 的指示符。但由于两个 bin 中可能存在某些值,因此您不可能定义 bin 限制。但你可以这样做:

x <- rpois(50,5)
y <- EqualFreq2(x,15)
table(y)
split(x,y)

原答案:

您可以轻松地为此使用cut()

EqualFreq <-function(x,n,include.lowest=TRUE,...){
    nx <- length(x)    
    id <- round(c(1,(1:(n-1))*(nx/n),nx))

    breaks <- sort(x)[id]
    if( sum(duplicated(breaks))>0 stop("n is too large.")

    cut(x,breaks,include.lowest=include.lowest,...)

}

这给出了:

set.seed(12345)
x <- rnorm(50)
table(EqualFreq(x,5))

 [-2.38,-0.886] (-0.886,-0.116]  (-0.116,0.586]   (0.586,0.937]     (0.937,2.2] 
             10              10              10              10              10 

x <- rpois(50,5)
table(EqualFreq(x,5))

 [1,3]  (3,5]  (5,6]  (6,7] (7,11] 
    10     13     11      6     10 

如您所见,对于离散数据,在大多数情况下,最佳的相等分箱是相当不可能的,但这种方法为您提供了可能的最佳分箱。

【讨论】:

  • 您也可以使用quantile 设置休息时间:table(cut(x,quantile(x),include.lowest=T))
  • @Joris, @James - 此函数在以下情况下中断: test = c(1,1,1,1,1,1,1,1,2,2) EqualFreq(test,2 )。理想的解决方案不会与数字中断相关联,而是与位置中断相关联。我会尝试制定一个解决方案,但如果有什么想法请告诉我
  • @James :基本相同(我手动计算分位数,以允许任何类型的分箱)
  • @SFun28 :您打算如何处理?您只有 2 个值,因此无法进行分箱。
  • @Joris - 肯定有 - 排序后将前五个值放入 bin1 中,将后五个值放入 bin2 中(此处已排序)。一些 1 将在 bin 1 中结束,而其他 1 将在 bin 2 中结束,并且这些 bin 将具有相同数量的观测值(或者如果 x 不能被 bin 数整除,则足够接近)
【解决方案2】:

这种事情也很容易通过使用(滥用?)lattice 中的条件绘图基础设施来解决,特别是函数co.intervals()

cutEqual <- function(x, n, include.lowest = TRUE, ...) {
    stopifnot(require(lattice))
    cut(x, co.intervals(x, n, 0)[c(1, (n+1):(n*2))], 
        include.lowest = include.lowest, ...)
}

这再现了@Joris 的出色回答:

> set.seed(12345)
> x <- rnorm(50)
> table(cutEqual(x, 5))

 [-2.38,-0.885] (-0.885,-0.115]  (-0.115,0.587]   (0.587,0.938]     (0.938,2.2] 
             10              10              10              10              10
> y <- rpois(50, 5)
> table(cutEqual(y, 5))

 [0.5,3.5]  (3.5,5.5]  (5.5,6.5]  (6.5,7.5] (7.5,11.5] 
        10         13         11          6         10

在后一种离散情况下,虽然它们具有相同的效果,但中断是不同的;相同的观察结果在相同的 bin 中。

【讨论】:

  • 你最后的答案真的敦促我更多地了解如何用 lattice 破解。似乎它有一些很好的滥用功能。谢谢小费+1
  • 非常感谢这个解决方案。继续学习有关 R 的新知识! (也感谢您对其他帖子的回复=)
  • 这个解决方案看起来不错,但是如果你想根据单个变量的间隔拆分数据帧,你会如何修改函数?
【解决方案3】:

怎么样?

a <- rnorm(50)
> table(Hmisc::cut2(a, m = 10))

[-2.2020,-0.7710) [-0.7710,-0.2352) [-0.2352, 0.0997) [ 0.0997, 0.9775) 
               10                10                10                10 
[ 0.9775, 2.5677] 
               10 

【讨论】:

  • 感谢 cut2 的提示(尽管 OP 的问题被证明具有不同的性质)
【解决方案4】:

classInt 库是“为映射或其他图形目的选择单变量类间隔”而创建的。你可以这样做:

dataset <- c(1,3,2,1,2,2) 

library(classInt)
classIntervals(dataset, 2, style = 'quantile')

其中2 是您想要的箱数,quantile style 提供分位数分隔符。有几个styles 可用于此功能:“fixed”、“sd”、“equal”、“pretty”、“quantile”、“kmeans”、“hclust”、 “bclust”、“fisher”或“jenks”。检查docs 了解更多信息。

【讨论】:

    【解决方案5】:

    这是一个处理错误的函数:'breaks' are not unique,并自动选择最接近您设置的n_bins值。

    equal_freq <- function(var, n_bins)
    {
      require(ggplot2)
    
      n_bins_orig=n_bins
    
      res=tryCatch(cut_number(var, n = n_bins), error=function(e) {return (e)})
      while(grepl("'breaks' are not unique", res[1]) & n_bins>1)
      {
        n_bins=n_bins-1
        res=tryCatch(cut_number(var, n = n_bins), error=function(e) {return (e)})
    
      }
      if(n_bins_orig != n_bins)
        warning(sprintf("It's not possible to calculate with n_bins=%s, setting n_bins in: %s.", n_bins_orig, n_bins))
    
      return(res)
    }
    

    例子:

    equal_freq(mtcars$carb, 10)
    

    检索分箱变量和以下警告:

    It's not possible to calculate with n_bins=10, setting n_bins in: 5.
    

    【讨论】:

      【解决方案6】:

      这是一个受@Joris 回答启发的单线解决方案:

      x <- rpois(50,5)
      binSize <- 5
      desiredFrequency = floor(length(x)/binSize)
      split(sort(x), rep(1:binSize, rep(desiredFrequency, binSize)))
      

      【讨论】:

        【解决方案7】:

        这是另一个使用 mltools 的解决方案。

        set.seed(1)
        x <- round(rnorm(20), 2)
        x.binned <- mltools::bin_data(x, bins = 5, binType = "quantile")
        table(x.binned)
        
        x.binned
        [-2.21, -0.622)   [-0.622, 0.1)    [0.1, 0.526)  [0.526, 0.844)    [0.844, 1.6] 
                      4               4               4               4               4 
        

        【讨论】:

        • 有没有办法将这个非常精美的排版表格转换为 hist() 的中断可以理解的向量??????非常感谢
        【解决方案8】:

        我们可以使用 cutr 包装 what = "rough",标签的外观可以根据口味定制:

        # devtools::install_github("moodymudskipper/cutr")
        library(cutr)
        smart_cut(c(1, 3, 2, 1, 2, 2), 2, "rough", brackets = NULL, sep="-")
        # [1] 1-2 2-3 1-2 1-2 2-3 2-3
        # Levels: 1-2 < 2-3
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-01-12
          • 1970-01-01
          • 1970-01-01
          • 2017-04-29
          • 1970-01-01
          • 2020-08-20
          • 1970-01-01
          相关资源
          最近更新 更多