【问题标题】:splitting a continuous variable into groups of equal number of elements - return numeric vector from bin values将连续变量分成相等数量的元素组 - 从 bin 值返回数值向量
【发布时间】:2016-09-19 15:12:24
【问题描述】:

我有一个连续变量,我想将其拆分为多个 bin,返回一个数值向量(长度等于我的原始向量),其值与 bin 的值相关。每个 bin 应该有大致相同数量的元素。

这个问题: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

这更好,因为现在返回值与 bin 的值相关。但它仍然不太理想,因为:

  • (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])
}

我的目标是找到更快、更优雅、更容易适应任何一个端点的东西,而不仅仅是手段。


编辑:

澄清一下:我想要的输出是:

  • (a) 相当于我现在在使用 cut2 的示例中可以实现的效果,但不需要将因子转换为数字。

  • (b) 如果可能,还可以轻松选择使用区间的任一端点,而不是中点。

【问题讨论】:

    标签: r


    【解决方案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 将区间拆分为多个等长的区间。

    【讨论】:

    • 好的,谢谢,这对功能和注释都有帮助。我的术语可能有点草率,-cut2 是一种获取具有相对元素数量相等的垃圾箱的方法,对吧?
    • 并非如此,如果您查看cut2 的结果,第一组包含四个元素,第二个只有一个,最后两个。函数cut不保证每个组的元素数量相同。
    • 如果你想拥有相同数量的元素,你应该订购它们,然后将它们分成大小相等的组。
    • 查看来自 ggplot2 的 cut_number 的文档,看起来它 尝试 近似相等,但不能保证它。 cut2 不是明确的一种或另一种方式,但可能大致相同。
    【解决方案2】:

    也许不是很优雅,但应该是高效的。试试这个功能:

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-31
      • 2017-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-18
      相关资源
      最近更新 更多