为了账号安全,请及时绑定邮箱和手机立即绑定

按组获取最高值

按组获取最高值

波斯汪 2019-09-02 09:50:41
这是一个示例数据框:d <- data.frame(  x   = runif(90),  grp = gl(3, 30)) 我想要d包含x每个值的前5个值的行的子集grp。使用base-R,我的方法是这样的:ordered <- d[order(d$x, decreasing = TRUE), ]    splits <- split(ordered, ordered$grp)heads <- lapply(splits, head)do.call(rbind, heads)##              x grp## 1.19 0.8879631   1## 1.4  0.8844818   1## 1.12 0.8596197   1## 1.26 0.8481809   1## 1.18 0.8461516   1## 1.29 0.8317092   1## 2.31 0.9751049   2## 2.34 0.9269764   2## 2.57 0.8964114   2## 2.58 0.8896466   2## 2.45 0.8888834   2## 2.35 0.8706823   2## 3.74 0.9884852   3## 3.73 0.9837653   3## 3.83 0.9375398   3## 3.64 0.9229036   3## 3.69 0.8021373   3## 3.86 0.7418946   3使用dplyr,我希望这可以工作:d %>%  arrange_(~ desc(x)) %>%  group_by_(~ grp) %>%  head(n = 5)但它只返回前5行。交换head的top_n整个的回报d。d %>%  arrange_(~ desc(x)) %>%  group_by_(~ grp) %>%  top_n(n = 5)我如何获得正确的子集?
查看完整描述

3 回答

?
哔哔one

TA贡献1854条经验 获得超8个赞

来自?top_n,关于wt论点:


用于排序[...] 的变量默认为 tbl中的最后一个变量 “。


数据集中的最后一个变量是“grp”,它不是你想要排名的变量,这就是你的top_n尝试“返回整个d”的原因。因此,如果您希望在数据集中按“x”排名,则需要指定wt = x。


set.seed(123)

d <- data.frame(

  x   = runif(90),

  grp = gl(3, 30))


d %>%

  group_by(grp) %>%

  top_n(n = 5, wt = x)

#            x grp

# 1  0.9404673   1

# 2  0.9568333   1

# 3  0.8998250   1

# 4  0.9545036   1

# 5  0.9942698   1

# 6  0.9630242   2

# 7  0.9022990   2

# 8  0.8578277   2

# 9  0.7989248   2

# 10 0.8950454   2

# 11 0.8146400   3

# 12 0.8123895   3

# 13 0.9849570   3

# 14 0.8930511   3

# 15 0.8864691   3


查看完整回答
反对 回复 2019-09-02
?
翻翻过去那场雪

TA贡献2065条经验 获得超13个赞

data.table太容易了......


library(data.table)

setorder(setDT(d), -x)[, head(.SD, 5), keyby = grp]

要么


setorder(setDT(d), grp, -x)[, head(.SD, 5), by = grp]

或者(对于大数据集应该更快,因为避免调用.SD每个组)


setorder(setDT(d), grp, -x)[, indx := seq_len(.N), by = grp][indx <= 5]

编辑:这是dplyr比较data.table(如果有人感兴趣)


set.seed(123)

d <- data.frame(

  x   = runif(1e6),

  grp = sample(1e4, 1e6, TRUE))


library(dplyr)

library(microbenchmark)

library(data.table)

dd <- copy(d)


microbenchmark(

  top_n = {d %>%

             group_by(grp) %>%

             top_n(n = 5, wt = x)},

  dohead = {d %>%

              arrange_(~ desc(x)) %>%

              group_by_(~ grp) %>%

              do(head(., n = 5))},

  slice = {d %>%

             arrange_(~ desc(x)) %>%

             group_by_(~ grp) %>%

             slice(1:5)},

  filter = {d %>% 

              arrange(desc(x)) %>%

              group_by(grp) %>%

              filter(row_number() <= 5L)},

  data.table1 = setorder(setDT(dd), -x)[, head(.SD, 5L), keyby = grp],

  data.table2 = setorder(setDT(dd), grp, -x)[, head(.SD, 5L), grp],

  data.table3 = setorder(setDT(dd), grp, -x)[, indx := seq_len(.N), grp][indx <= 5L],

  times = 10,

  unit = "relative"

)



#        expr        min         lq      mean     median        uq       max neval

#       top_n  24.246401  24.492972 16.300391  24.441351 11.749050  7.644748    10

#      dohead 122.891381 120.329722 77.763843 115.621635 54.996588 34.114738    10

#       slice  27.365711  26.839443 17.714303  26.433924 12.628934  7.899619    10

#      filter  27.755171  27.225461 17.936295  26.363739 12.935709  7.969806    10

# data.table1  13.753046  16.631143 10.775278  16.330942  8.359951  5.077140    10

# data.table2  12.047111  11.944557  7.862302  11.653385  5.509432  3.642733    10

# data.table3   1.000000   1.000000  1.000000   1.000000  1.000000  1.000000    10

添加速度稍慢的data.table解决方案:


set.seed(123L)

d <- data.frame(

    x   = runif(1e8),

    grp = sample(1e4, 1e8, TRUE))

setDT(d)

setorder(d, grp, -x)

dd <- copy(d)


library(microbenchmark)

microbenchmark(

    data.table3 = d[, indx := seq_len(.N), grp][indx <= 5L],

    data.table4 = dd[dd[, .I[seq_len(.N) <= 5L], grp]$V1],

    times = 10L

)

定时输出:


Unit: milliseconds

        expr      min       lq     mean   median        uq      max neval

 data.table3 826.2148 865.6334 950.1380 902.1689 1006.1237 1260.129    10

 data.table4 729.3229 783.7000 859.2084 823.1635  966.8239 1014.397    10


查看完整回答
反对 回复 2019-09-02
?
汪汪一只猫

TA贡献1898条经验 获得超8个赞

你需要head打电话给do。在下面的代码,.表示当前组(见说明...在do帮助页面)。


d %>%

  arrange_(~ desc(x)) %>%

  group_by_(~ grp) %>%

  do(head(., n = 5))

如akrun所述,slice是另一种选择。


d %>%

  arrange_(~ desc(x)) %>%

  group_by_(~ grp) %>%

  slice(1:5)


查看完整回答
反对 回复 2019-09-02
  • 3 回答
  • 0 关注
  • 496 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信