【问题标题】:How to bin ordered data by percentile for each id in R dataframe [r]如何为 R 数据帧 [r] 中的每个 id 按百分位排列有序数据
【发布时间】:2011-12-01 22:57:00
【问题描述】:

我有一个数据框,其中包含 70-80 行有序响应时间 (rt) 数据,每个人都有一个唯一的 id#(每个人的行数都不相同),每个人 228 人。我想将每个人的 RT 分成 5 个箱子。我希望第一个 bin 是他们最快的 20% RT,第二个 bin 是他们下一个最快的 20% RT,等等。每个 bin 应该有相同数量的试验(除非试验总数是奇数)。

我当前的数据框如下所示:

id     RT
7000   225
7000   250
7000   253
7001   189
7001   201
7001   225

我希望我的新数据框如下所示:

id   RT    Bin
7000  225    1
7000  250    1

让我的数据看起来像这样后,我将按 id 和 bin 聚合

我能想到的唯一方法是将数据拆分成一个列表(使用 split 命令),遍历每个人,使用 quantile 命令获取不同 bin 的断点,分配 bin 值(1-5) 到每个响应时间。这感觉很复杂(对我来说很难)。我遇到了一些麻烦,我将非常感谢有关如何简化此过程的任何帮助。谢谢。

【问题讨论】:

    标签: r dataframe percentile


    【解决方案1】:

    这是一个简单的旧 R 的答案。

    #make up some data
    df <- data.frame(rt = rnorm(60), id = rep(letters[1:3], rep(20)) )
    
    #and this is all there is to it
    df <- df[order(df$id, df$rt),]
    df$bin <- rep( unlist( tapply( df$rt, df$id, quantile )), each = 4)
    

    您会注意到,使用的quantile 命令可以设置为使用任何分位数。默认值是五分位数,但如果你想要十分位数,请使用

    quantile(x, seq(0, 1, 0.1))
    

    在上面的函数中。

    上面的答案有点脆弱。它需要相同数量的 RTs/id,我没有告诉你如何获得神奇的数字 4。但是,它在大型数据集上运行也非常快。如果您想在基础 R 中获得更强大的解决方案。

    library('Hmisc')
    df <- df[order(df$id),]
    df$bin <- unlist(lapply( unique(df$id), function(x) cut2(df$rt[df$id==x], g = 5) ))
    

    这比第一个解决方案强大得多,但速度没有那么快。对于您不会注意到的小型数据集。

    【讨论】:

    • 这个聚合命令返回的值是多少?我想要的是每个 id 的 5 个值,第一个值是该 id 的最快 x 试验量的平均值,下一个 bin 是他们下一个最快的 x 试验量。每个 bin 应由相同数量的 Trial 组成(当总 Trial 计数为偶数时)。
    • 查看应该做你想做的修改
    • 谢谢,约翰。我已经运行了您修改后的解决方案。我不明白为什么 rts 没有上升。切割点中包含的值的平均值应该随着切割点变大而上升,不是吗?
    • 哪种解决方案,脆弱的快速一个或更健壮(比 ddply 快)的一个?
    【解决方案2】:

    @Chase 给出的答案将范围分成 5 组等长(端点的差异)。您似乎想要的是 pentiles(5 组,每组数量相同)。为此,您需要 Hmisc 中的 cut2 函数

    library("plyr")
    library("Hmisc")
    
    dat <- data.frame(id = rep(1:10, each = 10), value = rnorm(100))
    
    tmp <- ddply(dat, "id", transform, hists = as.numeric(cut2(value, g = 5)))
    

    tmp 现在有你想要的

    > tmp
        id       value hists
    1    1  0.19016791     3
    2    1  0.27795226     4
    3    1  0.74350982     5
    4    1  0.43459571     4
    5    1 -2.72263322     1
    ....
    95  10 -0.10111905     3
    96  10 -0.28251991     2
    97  10 -0.19308950     2
    98  10  0.32827137     4
    99  10 -0.01993215     4
    100 10 -1.04100991     1
    

    对于每个id,每个hists 中的编号相同

    > table(tmp$id, tmp$hists)
    
         1 2 3 4 5
      1  2 2 2 2 2
      2  2 2 2 2 2
      3  2 2 2 2 2
      4  2 2 2 2 2
      5  2 2 2 2 2
      6  2 2 2 2 2
      7  2 2 2 2 2
      8  2 2 2 2 2
      9  2 2 2 2 2
      10 2 2 2 2 2
    

    【讨论】:

    • 是的!我是对的,谢谢你充实了这一点。 (如果不清楚,请参阅下面的评论)
    • 对不起,@Chase,在我开始创作之前我没有看到你的评论。
    【解决方案3】:

    这是一个使用包 plyrcut 函数的可重现示例:

    dat <- data.frame(id = rep(1:10, each = 10), value = rnorm(100))
    
    ddply(dat, "id", transform, hists = cut(value, breaks = 5))
    
        id       value             hists
    1    1 -1.82080027     (-1.94,-1.41]
    2    1  0.11035796     (-0.36,0.166]
    3    1 -0.57487134    (-0.886,-0.36]
    4    1 -0.99455189    (-1.41,-0.886]
    ....
    96  10 -0.03376074    (-0.233,0.386]
    97  10 -0.71879488   (-0.853,-0.233]
    98  10 -0.17533570    (-0.233,0.386]
    99  10 -1.07668282    (-1.47,-0.853]
    100 10 -1.45170078    (-1.47,-0.853]
    

    如果您想要返回简单的整数值而不是 bin,则将 labels = FALSE 传递给 cut

    【讨论】:

    • 也许我的问题不清楚,对于每个 id,我希望将相同数量的试验分成 5 个箱子。例如,一个拥有 80 rts 的人将有 16 个试验的 5 个 bin,其中 bin 1 是最快的 16 个试验,而 bin 5 是最慢的。您知道实现此目的的方法吗?
    • @Matt Chase 的回答正是您所描述的。你试过了吗?
    • 我做到了。我很欣赏蔡斯的解决方案。但我不清楚我最初要求的是什么。我需要每个 bin 由相同数量的 rts 组成。在 Chases 解决方案中,hist 创建 5 个 bin,但每个 bin 由不同数量的 rts 组成。
    • @Matt - 啊,明白了,对不起,我误解了。我现在没有时间,但我 99% 确信 Hmisc 包中的 cut2 函数有一个额外的参数可以为你做这个,我相信它是 g 参数。如果没有,我今天晚些时候会处理一些事情。
    猜你喜欢
    • 2021-12-13
    • 1970-01-01
    • 2019-03-02
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-20
    • 2021-09-12
    相关资源
    最近更新 更多