【问题标题】:R - cut2 - one bin for zeros and 10 for everything elseR - cut2 - 一个 bin 用于零,10 用于其他所有内容
【发布时间】:2017-09-26 15:26:34
【问题描述】:

我有一个偏态分布的数据集,我想将其划分为具有相同观察数的 bin - 除了偏态。

为了澄清,我有大量的零,以及相对较少的 > 0 观察值。

如果我使用 cut2 将值分箱到 10 个箱中,包括零,我会得到以下结果。

library(data.table)
library(Hmisc)

DT<-data.table(x=rep(0,100), y=rep(0,100))
DT<-rbind(DT, data.table(x=seq(1:100),y=seq(1:100)))
DT
       x   y
  1:   0   0
  2:   0   0
  3:   0   0
  4:   0   0
  5:   0   0
 ---        
196:  96  96
197:  97  97
198:  98  98
199:  99  99
200: 100 100

只看x

data.table(DT[, cut2(x, g=10)])[,.N, by=V1]
         V1   N
1:        0 100
2: [ 1, 21)  20
3: [21, 41)  20
4: [41, 61)  20
5: [61, 81)  20
6: [81,100]  20

因此,100 个零的存在已将 bin 移动到将高于零的观测值聚集到 5 个桶中的地步。

如果我专门过滤掉零并应用 10 个 bin,我会按预期得到以下结果...

data.table(DT[x>0, cut2(x, g=10)])[,.N, by=V1]
          V1  N
 1: [ 1, 11) 10
 2: [11, 21) 10
 3: [21, 31) 10
 4: [31, 41) 10
 5: [41, 51) 10
 6: [51, 61) 10
 7: [61, 71) 10
 8: [71, 81) 10
 9: [81, 91) 10
10: [91,100] 10

我想做的是有 11 个桶 - 一个用于零,10 个用于非零。我当然可以通过 2 个单独的操作来应用它

DT[x==0, bin:=cut2(x, g=1)]
Warning message:
In min(diff(x.unique)) : no non-missing arguments to min; returning Inf

DT[x>0, bin:=cut2(x, g=10)]
DT[, .(min(x), max(x)), by=bin]
         bin V1  V2
 1:        0  0   0
 2: [ 1, 11)  1  10
 3: [11, 21) 11  20
 4: [21, 31) 21  30
 5: [31, 41) 31  40
 6: [41, 51) 41  50
 7: [51, 61) 51  60
 8: [61, 71) 61  70
 9: [71, 81) 71  80
10: [81, 91) 81  90
11: [91,100] 91 100

但是我必须对 y 重复同样的 2 次操作。我的实际数据表大约有 30 列,所以我想知道是否有:

  1. 允许我将这两个操作一起应用于单个列的快捷方式?
  2. 允许我将这两个操作应用于包含 30 列的列表的其他快捷方式?

我能看到的关键部分是过滤器部分 - 分布都向零倾斜,但每列包含不同数量的观察值,因此会有不同的 bin。

任何指针将不胜感激。

大卫

附言希望帖子的布局可以让您剪切和粘贴代码 - 为了清楚起见,我包含了输出,但如果有问题,请告诉我。

编辑 在查看@Eddi 的答案并应用到我的数据后,我可以看到我提供的数据与我实际运行的数据存在问题。

这些是在我的数据上使用 Eddi 的方法运行的结果(名称被屏蔽)...

> data.table(XXX[, cut2(yyy, m = 
sum(yyy > 0)/10)])[, .N, by = V1]
              V1   N
 1: [   0,    4) 284
 2: [3891,72337] 264
 3: [1212, 3891) 264
 4: [ 519, 1212) 264
 5: [ 208,  519) 263
 6: [  49,  101) 267
 7: [ 101,  208) 263
 8: [  11,   24) 258
 9: [  24,   49) 263
10: [   4,   11) 252
 > XXX[yyy==0, .N,]
 [1] 74
> XXX[yyy>=0, .N,]
[1] 2642

我更新了测试数据集以重现如下结果 - 主要是将潜在值的范围扩展到 70,000 并随机而不是按顺序生成它们。还生成了 2700 个,而不是我正在使用的 100 个左右

DT<-data.table(x=rep(0,100), y=rep(0,100))
DT<-rbind(DT, data.table(x=runif(2600,1,70000),y=runif(2600,1,70000)))
DT
data.table(DT[, cut2(x, m = sum(x > 0)/10)])[, .N, by = V1]

           V1   N
 1: [    0, 4798) 270
 2: [41289,48407) 270
 3: [11482,18413) 270
 4: [48407,55678) 270
 5: [55678,62157) 270
 6: [33040,41289) 270
 7: [25470,33040) 270
 8: [ 4798,11482) 270
 9: [62157,69983] 270
10: [18413,25470) 270

因此,这已将零桶卷入其余 10 个桶中 - 诚然,这并没有对分布产生巨大影响,但它是这种方法似乎略有失效的列之一。

对于测试数据的错误表示歉意,我没有预料到这种影响。

欢迎任何关于如何进行的想法......

干杯

大卫

【问题讨论】:

  • 按照你的方式分别对 0 和非零进行分箱,并在列上运行 for 循环。
  • 嗨@Eddi,好的,当然——这最终是我的选择,但在看到你的提议后,我用 R 学到了更多技巧,所以谢谢你。跨度>

标签: r data.table hmisc


【解决方案1】:

在 Eddi 的反馈和我自己对此进行的实验之后,我决定对列列表使用 for 循环,特别是先将零分箱,然后分别对非零进行分箱。

DT<-data.table(x=rep(0,100), y=rep(0,100))
DT<-rbind(DT, data.table(x=runif(100,1,10000),y=runif(100,1,10000)))
DT


cols <- data.table(col_name=c("x","y"))


for(col in 1:nrow(cols)){

    DT[get(cols[col, col_name])==0,(paste(cols[col,col_name],"_bin",sep="")):= cut2(get(cols[col, col_name]),g=1)]
    DT[get(cols[col, col_name])>0,(paste(cols[col, col_name],"_bin",sep="")):= cut2(get(cols[col, col_name]),g=10)]

}  

data.table(DT[, cut2(x, m = sum(x > 0)/10)])[, .N, by = V1]

                   V1   N
 1:              0.00 100
 2: [2540.22,4009.79)  10
 3: [4923.05,5736.81)  10
 4: [4009.79,4923.05)  10
 5: [ 910.57,1563.99)  10
 6: [5736.81,6121.23)  10
 7: [   9.77, 910.57)  10
 8: [9240.77,9957.27]  10
 9: [1563.99,2540.22)  10
10: [6121.23,7759.80)  10
11: [7759.80,9240.77)  10

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-13
    • 2017-12-14
    • 2020-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    相关资源
    最近更新 更多