2016-09-19 29 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