R 中的装箱程序?

A binning procedure in R?

我正在努力将以下装箱 "algorithm/procedure" 放入 R code/script 中,这可能类似于用于装箱核密度估计的那些:

假设我们有一些数据:

set.seed(12345) # setting seed
x<-rnorm(100)   # generating data

和用于估计的网格(例如核密度估计):

y<-seq(from=min(x)-1, to=max(x)+1, by=0.01) # grid for binning

  1. objective 是将 y 分箱成一些相等的 intervals/bins 以便每个分箱包含至少一个来自 x 的观察值(垃圾箱数量 = 不允许空垃圾箱)。对于这个特定的例子,我知道这样的垃圾箱数量等于 17 但我希望 R 自动确定这样的 "optimal/maximum" 垃圾箱数量和相应的垃圾箱 y

  2. 说确定了所需的等于 intervals/bins 的数量,然后可以使用(至少从我的主动谷歌搜索中)以下内容到 bin y:

nbins<-cut(y, 17) # binning

哪个做得很好,因为它完全按照我想要的方式拆分 y,但是如何确定每个 bin 的中心(也许使用 median()?)以及 x 哪个落入每个垃圾箱?

有一个有趣的包 binr,功能非常好,但是,它似乎并没有提供我正在寻找的东西。如果有任何提示、提示、建议,我将不胜感激 ...

EDIT: an example of a code with which I ended up with for my calculations.

首先,我想特别感谢@missuse 的帮助、努力和投入。其次,我想为我对某些 base R 函数的无知(希望是由于缺乏 R 和一般编程经验)表示歉意。

我用@missuse为我的计算开发的代码进行了改造和试验,然而,遗漏x的问题不断出现,并且经常需要针对不同的数据集进行手动调整。特别是,当我试验由我的数据样本分位数确定的断点时。另外 cut 函数在我看来似乎相当敏感(注意:由于我的目标、数据等原因,这可能是相当主观的)。因此,前几天厌倦了不断调整和为各种 R 函数执行 help() 命令,hist() 来拯救我并解决了几乎所有的装箱问题。所以下面是非常简单的说明,以确定有多少 x 落入每个 bin 以及如何确定每个 bin 的 bin 中心:

hist(x, breaks=c(-5:5), plot=FALSE)$counts # for bin counts 
hist(x, breaks=c(-5,5), plot=FALSE)$mids   # for bin centers

以上我假设 select 需要休息,您可以根据需要的方式构建基于 cut 函数的函数,并相应地切割网格以进行估计。下面的@missuse 为使用 cut 设置中断提供了良好的基础,只需确保您的数据跨越 hist() 中的 breaks 规范。

可能是这样的:

数据:

 set.seed(12345) # setting seed
 x<-rnorm(100)
 y<-seq(from=min(x)-1, to=max(x)+1, by=0.01) 
 nbins<-cut(y, 17)

第 1 步:

对于所有可能的切割,查找 x 的任何元素是否在所有 bin 中:

p =lapply(3 : length(x), function(i){
  nbins<-cut(y, i)
  z = lapply(levels(nbins), function(j) y[nbins == j])
  sumi = lapply(z, function(i) {
    mini = min(i)
    maxi = max(i)
    sum(mini <= x & x <= maxi)
  }
  )
  return(sum(unlist(sumi)>0) == length(sumi))
}
)

which(unlist(p)), only first 4 satisfy the rule, so 3, 4, 5, 6 

第 2 步:

根据 bin 将值放入列表中:

z = lapply(levels(nbins), function(x) y[nbins == x] )

对每个列表项执行感兴趣的功能

lapply(z, median) #median for each bin

lapply(z, function(i) {
  mini = min(i)
  maxi = max(i)
  sum(mini <= x & x <= maxi)
}
) #number of elements of x in each bin

根据结果,一些容器中有 0 个来自 x 的元素,因此容器 17 无法解决您在第 1 步中遇到的问题。

编辑:关于缺少 x:

的问题
sum(unlist(lapply(z, function(i) {
  mini = min(i)
  maxi = max(i)
  sum(mini <= x & x <= maxi)
}
))) is less than 100 in many cases

缺少哪些 x:

nbins<-cut(y, 8) 
    z = lapply(levels(nbins), function(x) y[nbins == x])
    gix = lapply(z, function(i) {
      mini = min(i)
      maxi = max(i)
      x[mini <= x & x <= maxi]
    }
    )
  x[!x %in% unlist(gix)]

 #-1.6620502 -0.8115405 

所以它们应该在垃圾箱 (-1.67,-0.812](-0.812,0.0446] 中 并且实际上接近 bin 截止值。

这是因为 y 四舍五入到两位小数。例如,如果我们将一个序列分箱:0.01、0.02、0.03 和 0.04,并将其分成 2 个分箱,以 0.025 的比例拆分数据,我们将得到分箱 1:0.01 - 0.02 和分箱 2:0.03 - 0.04,如果我们随后尝试要分配 0.01 - 0.04 范围内的一些随机 x 值,仅基于 bin 中存在的 y 值,我们不会分配 0.02 - 0.03 范围内的任何值 - 因此缺少值。

一个可能的解决方案是将 x 舍入为 2,因为您已经将 seq 舍入为 2。或者用 y 值四舍五入到 4 - 6 位小数和相应地舍入 x。或者不是根据 bin i 中的 min(yi)max(yi) 分配 x,而是将 min(yi) <= x 替换为 max(yi-1) < x(bin i-1 中的 max(yi)),并将 x <= max(yi) 替换为 x < min(yi+1)。 这是最简单的解决方案,x 保留 2 位小数。

p =lapply(2 : length(x), function(i){
  nbins<-cut(y, i)
  z = lapply(levels(nbins), function(j) y[nbins == j])
  sumi = lapply(z, function(i) {
    mini = min(i)
    maxi = max(i)
    p = round(x, 2)
    sum(mini <= p & p <= maxi)
  }
  )
  return(sum(unlist(sumi)>0) == length(sumi))
}
)

至少可以解决缺少 x 个元素的问题

优化问题的解也是一样

which(unlist(p)),只有前4个满足规则,所以3,4,5,6