2016-09-19 31 views
0

我有要分成倉連續變量,返回一個數值向量(長度等於我的原始向量),其值與到箱子的價值。每個垃圾桶的元素數量應該大致相同。分裂連續變量分成相等數目的元素的基團 - 從箱返回數字矢量值

這個問題:splitting a continuous variable into equal sized groups介紹了一些相關情況的技術。舉例來說,如果我開始與

x = c(1,5,3,12,5,6,7) 

我可以使用cut()獲得:

cut(x, 3, labels = FALSE) 
[1] 1 2 1 3 2 2 2 

這是不可取的,因爲該因素的值只是連續整數,他們沒有直接關係到底層原始值在我的向量中。

另一種可能性是cut2:例如:

library(Hmisc) 
cut2(x, g = 3, levels.mean = TRUE) 
[1] 3.5 3.5 3.5 9.5 3.5 6.0 9.5 

這更好,因爲現在的返回值涉及到倉的值。它仍然是不夠理想雖然因爲:

  • 的(a)它產生一個因子,其然後需要被轉換爲數字(參見,e.g.),這是既明智緩慢和笨拙的代碼。
  • (B)理想情況下,我想是不是隻是手段能夠選擇是否使用該區間的頂部或底部終點。

我知道,也有使用從cutcut2的因素返回正則表達式來獲得區間的頂部或底部點選項。這些看起來過於繁瑣。

這只是需要一些不那麼優雅的黑客攻擊的情況嗎?或者,有沒有一些比較容易的功能來做到這一點?

我目前最好的努力是如下:

MyDiscretize = function(x, N_Bins){ 
    f = cut2(x, g = N_Bins, levels.mean = TRUE) 
    return(as.numeric(levels(f))[f]) 
} 

我的目標是更快地找到的東西,更優雅,並且容易適應爲使用的端點,而不僅僅是手段。


編輯:

澄清:我需要的輸出將是:

  • (一)一個相當於什麼,我可以用cut2但沒有馬上實現的例子需要將該因子轉換爲數字。

  • (b)中如果可能的話,能夠將也易選擇使用的,而不是中點任一的間隔的端點,。

回答

1

使用ave這樣的:

考慮:

x = c(1,5,3,12,5,6,7) 

平均:

ave(x,cut2(x,g = 3), FUN = mean) 
[1] 3.5 3.5 3.5 9.5 3.5 6.0 9.5 

敏:

ave(x,cut2(x,g = 3), FUN = min) 
[1] 1 1 1 7 1 6 7 

最大:

ave(x,cut2(x,g = 3), FUN = max) 
[1] 5 5 5 12 5 6 12 

或標準偏差:

ave(x,cut2(x,g = 3), FUN = sd) 
[1] 1.914854 1.914854 1.914854 3.535534 1.914854  NA 3.535534 

注意NA導致在時間間隔只有一個數據點。

希望這是你所需要的。

注意:
cut2中的參數g是分位數組的數量。組可能沒有相同數量的數據點,並且間隔可能不具有相同的長度。
另一方面,cut將間隔分成幾個等長。

+0

好的,謝謝,這是有用的,功能和說明。我可能在我的術語中一直sl - , - 'cut2'是一種獲取*相對數量相等的元素的箱子,對嗎? –

+1

不是真的,如果你看看'cut2'的結果,第一組包含四個元素,第二個只有一個,最後兩個。函數'cut'並不能保證每個組都有相同數量的元素。 –

+0

如果你想擁有相同數量的元素,你應該訂購它們,然後將它們分成相同大小的組。 –

1

也許不是很高雅,但應該是高效的。試試這個功能:

myCut<-function(x,breaks,retValues=c("means","highs","lows")) { 
    retValues<-match.arg(retValues) 
    if (length(breaks)!=1) stop("breaks must be a single number") 
    breaks<-as.integer(breaks) 
    if (is.na(breaks)||breaks<2) stop("breaks must greater than or equal to 2") 
    intervals<-seq(min(x),max(x),length.out=breaks+1) 
    bins<-findInterval(x,intervals,all.inside=TRUE) 
    if (retValues=="means") return(rowMeans(cbind(intervals[-(breaks+1)],intervals[-1]))[bins]) 
    if (retValues=="highs") return(intervals[-1][bins]) 
    intervals[-(breaks+1)][bins] 
} 
x = c(1,5,3,12,5,6,7) 
myCut(x,3) 
#[1] 2.833333 6.500000 2.833333 10.166667 6.500000 6.500000 6.500000 
myCut(x,3,"highs") 
#[1] 4.666667 8.333333 4.666667 12.000000 8.333333 8.333333 8.333333 
myCut(x,3,"lows") 
#[1] 1.000000 4.666667 1.000000 8.333333 4.666667 4.666667 4.666667