2017-09-26 51 views
1

我有一個偏斜分佈的數據集,我想用相同數量的觀測值分成兩個分箱 - 除了歪斜。R - cut2 - 一個零分區和10個其他分區

爲了澄清,我有大量的零和相對較少的> 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個零的存在已經轉移倉到零以上的觀察結果編成5桶中的點。

如果我特意篩選出零和應用10個箱,我得到預期下面...

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 

但是我不得不重複這些相同的2操作爲y。我的實際數據表大約有30列,所以我想知道是否有:

  1. 一個快捷方式,允許我將這兩個操作一起應用於單列?
  2. 另一個捷徑允許我將這兩個操作應用於30列的列表?

我可以看到的關鍵點是過濾器部分 - 分佈都偏向零,但每列包含不同數量的觀察值,並且會有不同的箱子。

任何指針,將不勝感激。

大衛

p.s.希望帖子的佈局能夠讓你可以剪切和粘貼代碼 - 爲了清晰起見,我包括了輸出,但如果有問題,請告訴我。

編輯 審查@ EDDI的答案,並應用到我的數據後,我可以看到,有一個與我提供了VS,我實際運行的數據中的數據有問題。

這些都是使用我的數據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

按照您的方式分別對0和非零進行合併,然後在列上運行for循環。 – eddi

+0

嗨@Eddi,好的確定 - 這是我最後的選擇,但在看到您的提案後,我已經與R學了更多技巧,所以非常感謝。 – Bravid

回答

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