【问题标题】:Label quantile by group with varying group sizes按具有不同组大小的组标记分位数
【发布时间】:2016-07-21 17:53:58
【问题描述】:

我的组(“名称”变量)中,我想将值分成四分位数。并为变量“值”创建一个四分位标签列。由于组大小不同,对于不同组的四分位范围变化在下面的代码中,仅将四分位数除以整体值,导致所有组相同的四分位数 范围

dt<-data.frame(name=c(rep('a',8),rep('b',4),rep('c',5)),value=c(1:8,1:4,1:5))
dt
dt.2<-dt%>% group_by(name)%>% mutate(newcol=
cut(value,breaks=quantile(value,probs=seq(0,1,0.25),na.rm=TRUE),include.lowest=TRUE))
dt.2
str(dt.2)

数据:

   name value
1     a     1
2     a     2
3     a     3
4     a     4
5     a     5
6     a     6
7     a     7
8     a     8
9     b     1
10    b     2
11    b     3
12    b     4
13    c     1
14    c     2
15    c     3
16    c     4
17    c     5

上述代码的输出。 更新:问题不在于 newcol 是因素,而是 necol 在所有不同组中具有相同的四分位数范围。比如名字b,取值是1-4,但四分位范围有3-5,不分分组,都是从min(value)到max(value)推导出来的。

 name value newcol
   <fctr> <int> <fctr>
1       a     1  [1,2]
2       a     2  [1,2]
3       a     3  (2,3]
4       a     4  (3,5]
5       a     5  (3,5]
6       a     6  (5,8]
7       a     7  (5,8]
8       a     8  (5,8]
9       b     1  [1,2]
10      b     2  [1,2]
11      b     3  (2,3]
12      b     4  (3,5]
13      c     1  [1,2]
14      c     2  [1,2]
15      c     3  (2,3]
16      c     4  (3,5]
17      c     5  (3,5]

期望的输出

   name value newcol/quartile label

1       a     1  1
2       a     2  1
3       a     3  2
4       a     4  2
5       a     5  3
6       a     6  3
7       a     7  4
8       a     8  4
9       b     1  1
10      b     2  2
11      b     3  3
12      b     4  4
13      c     1  1
14      c     2  2
15      c     3  3
16      c     4  4
17      c     5  4

【问题讨论】:

  • 您可以强制转换为numeric,因为cut 输出为factor,即as.numeric(cut(... 或使用findInterval
  • @akrun 感谢您指出获取四分位数数字标签的方法。但问题是 newcol 在所有不同的组中具有相同的四分位数范围。我将更新问题以澄清这一点。

标签: r dplyr data-manipulation


【解决方案1】:

按照拆分-应用-组合框架,您可以按照以下方式进行操作。

dt<-data.frame(name=c(rep('a',8),rep('b',4),rep('c',5)),value=c(1:8,1:4,1:5))

split_dt <- lapply(split(dt, dt$name), 
                   transform, 
                   quantlabel = as.numeric(
cut(value, breaks = quantile(value, probs = seq(0,1,.25)), include.lowest = T)))

dt <- unsplit(split_dt, dt$name)

   name value quantlabel
1     a     1          1
2     a     2          1
3     a     3          2
4     a     4          2
5     a     5          3
6     a     6          3
7     a     7          4
8     a     8          4
9     b     1          1
10    b     2          2
11    b     3          3
12    b     4          4
13    c     1          1
14    c     2          1
15    c     3          2
16    c     4          3
17    c     5          4

编辑:有一种data.table 方式

this post 之后,如果性能是一个问题,我们可以使用data.table 包:

library(data.table)
dt<-data.frame(name=c(rep('a',8),rep('b',4),rep('c',5)),value=c(1:8,1:4,1:5))
dt.t <- as.data.table(dt)
dt.t[,quantlabels := as.numeric(cut(value, breaks = quantile(value, probs = seq(0,1,.25)), include.lowest = T)), name]

    name value quantlabels
 1:    a     1           1
 2:    a     2           1
 3:    a     3           2
 4:    a     4           2
 5:    a     5           3
 6:    a     6           3
 7:    a     7           4
 8:    a     8           4
 9:    b     1           1
10:    b     2           2
11:    b     3           3
12:    b     4           4
13:    c     1           1
14:    c     2           1
15:    c     3           2
16:    c     4           3
17:    c     5           4

编辑:还有dplyr方式

我们可以按照@akrun 的建议使用as.numeric(这是我们为其他解决方案所做的):

dt %>%
    group_by(name) %>%
    mutate(quantlabel = 
               as.numeric(
                   cut(value, 
                       breaks = quantile(value, probs = seq(0,1,.25)), 
                       include.lowest = T)))

请注意,如果您想要标签本身,请使用as.character

dt %>%
    group_by(name) %>%
    mutate(quantlabel = as.character(cut(value, breaks = quantile(value, probs = seq(0,1,.25)), include.lowest = T)))

Source: local data frame [17 x 3]
Groups: name [3]

     name value quantlabel
   <fctr> <int>      <chr>
1       a     1   [1,2.75]
2       a     2   [1,2.75]
3       a     3 (2.75,4.5]
4       a     4 (2.75,4.5]
5       a     5 (4.5,6.25]
6       a     6 (4.5,6.25]
7       a     7   (6.25,8]
8       a     8   (6.25,8]
9       b     1   [1,1.75]
10      b     2 (1.75,2.5]
11      b     3 (2.5,3.25]
12      b     4   (3.25,4]
13      c     1      [1,2]
14      c     2      [1,2]
15      c     3      (2,3]
16      c     4      (3,4]
17      c     5      (4,5]

【讨论】:

  • 谢谢!您的代码看起来与我的代码非常相似,并且可以正常工作。但我想知道为什么这里的 group_by 没有传递到我的代码中。
  • @Phdaml 我不是dplyr 专家,所以我不完全确定为什么它不起作用。
  • 我知道为什么我的 group by 不工作了。我以某种方式卸载了 dplyr 包,但运行代码后没有显示错误。
  • 如果中断次数大于观察次数怎么办?我设置数据,使每组的观察值大于 4,因此四分位数是可行的。除了过滤掉观察数小于中断数的情况,我还能做些什么来给他们一个更小的中断数?
猜你喜欢
  • 2023-01-03
  • 2021-06-23
  • 2020-08-15
  • 2021-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-31
  • 1970-01-01
相关资源
最近更新 更多