【问题标题】:dplyr filter: Get rows with minimum of variable, but only the first if multiple minimadplyr 过滤器:获取变量最少的行,但如果有多个最小值,则仅获取第一行
【发布时间】:2014-02-14 00:23:51
【问题描述】:

我想使用dplyr 创建一个分组过滤器,在每个组内只返回具有变量x 最小值的行。

我的问题是:正如预期的那样,在多个最小值的情况下 all 具有最小值的行被返回。但就我而言,如果存在多个最小值,我只想要第一行。

这是一个例子:

df <- data.frame(
A=c("A", "A", "A", "B", "B", "B", "C", "C", "C"),
x=c(1, 1, 2, 2, 3, 4, 5, 5, 5),
y=rnorm(9)
)

library(dplyr)
df.g <- group_by(df, A)
filter(df.g, x == min(x))

正如所料,所有最小值都返回:

Source: local data frame [6 x 3]
Groups: A

  A x           y
1 A 1 -1.04584335
2 A 1  0.97949399
3 B 2  0.79600971
4 C 5 -0.08655151
5 C 5  0.16649962
6 C 5 -0.05948012

使用 ddply,我会以这种方式处理任务:

library(plyr)
ddply(df, .(A), function(z) {
    z[z$x == min(z$x), ][1, ]
})

...有效:

  A x           y
1 A 1 -1.04584335
2 B 2  0.79600971
3 C 5 -0.08655151

问:有没有办法在 dplyr 中解决这个问题?(出于速度原因)

【问题讨论】:

  • filter(df.g, rank(x) == 1) ?
  • @FelixS,rank(x)==1 是否给出了预期的结果?
  • @hadley, 1) 我不认为min_rank 在这里有帮助。他需要第一个最小值(查看plyr 解决方案)。 2) 无论您编写何种编程语言,rank 的算法复杂度(ties=min、max、first 等)都将比仅计算 min 更大。
  • @Arun:没错,只有rank(x, ties.method="first")==1 有效,因为 min 和 min_rank 不区分多个最小值。
  • @hadley,我仍然不明白这如何让您认为 which.min 是过早的优化。 AFAIK 这是一个自然的选择,读起来好,容易理解,快,因为它也恰好是 O(n)。

标签: r dplyr


【解决方案1】:

dplyr 提供slice_min 函数,使用参数with_ties = FALSE 完成这项工作

library(dplyr)

df %>% 
  group_by(A) %>% 
  slice_min(x, with_ties = FALSE)

输出:

# A tibble: 3 x 3
# Groups:   A [3]
A         x      y
<fct> <dbl>  <dbl>
1 A         1  0.273
2 B         2 -0.462
3 C         5  1.08 

【讨论】:

  • 这是我最喜欢的答案!
【解决方案2】:

来这里是为了寻找一种方法来与多个人一起做这件事。我相信这将给最后十名,打破平局

df.g %>%
top_n(-10,row_number(x))

【讨论】:

    【解决方案3】:

    更新

    在 dplyr >= 0.3 的情况下,您可以将 slice 函数与 which.min 结合使用,这将是我最喜欢执行此任务的方法:

    df %>% group_by(A) %>% slice(which.min(x))
    #Source: local data frame [3 x 3]
    #Groups: A
    #
    #  A x          y
    #1 A 1  0.2979772
    #2 B 2 -1.1265265
    #3 C 5 -1.1952004
    

    原答案

    对于样本数据,也可以使用两个filter一个接一个:

    group_by(df, A) %>% 
      filter(x == min(x)) %>% 
      filter(1:n() == 1)
    

    【讨论】:

    • 我发现do(head) 更容易阅读,df %&gt;% group_by(A) %&gt;% filter(x == min(x)) %&gt;% do(head(.,1))
    • @baptiste 看起来确实不错(但是,当我运行它时,我收到一条错误消息Error: expecting a single value) - 你知道为什么吗?
    • 不确定,也许我们使用的是不同的版本;我有dplyr_0.2, magrittr_1.0.0
    • 好的,所以问题是我仍在运行 dplyr 0.1.3。谢谢
    • 我更愿意在这里使用top_n,但由于关系密切,这种方法可能是明显的赢家——绝对是在性能方面(与arrange %&gt;% slice相比)。
    【解决方案4】:

    另一种方法:

    set.seed(1)
    x <- data.frame(a = rep(1:2, each = 10), b = rnorm(20))
    x <- dplyr::arrange(x, a, b)
    dplyr::filter(x, !duplicated(a))
    

    结果:

      a          b
    1 1 -0.8356286
    2 2 -2.2146999
    

    也可以很容易地适应在每个组中获取具有最大值的行。

    【讨论】:

      【解决方案5】:

      我喜欢 sqldf 的简单性..

      sqldf("select A,min(X),y from 'df.g' group by A")
      

      输出:

      A min(X)          y
      
      1 A      1 -1.4836989
      
      2 B      2  0.3755771
      
      3 C      5  0.9284441
      

      【讨论】:

        【解决方案6】:

        这可以通过将row_number 与group_by 结合使用来完成。 row_number 通过不仅按值而且按向量内的相对顺序分配等级来处理平局。获取最小值为x的每个组的第一行:

        df.g <- group_by(df, A)
        filter(df.g, row_number(x) == 1)
        

        有关更多信息,请参阅 dplyr vignette on window functions。

        【讨论】:

          【解决方案7】:

          为了完整起见:这是最终的dplyr 解决方案,源自@hadley 和@Arun 的cmets:

          library(dplyr)
          df.g <- group_by(df, A)
          filter(df.g, rank(x, ties.method="first")==1)
          

          【讨论】:

            【解决方案8】:

            对于它的价值,这里有一个data.table 解决方案,给那些可能感兴趣的人:

            # approach with setting keys
            dt <- as.data.table(df)
            setkey(dt, A,x)
            dt[J(unique(A)), mult="first"]
            
            # without using keys
            dt <- as.data.table(df)
            dt[dt[, .I[which.min(x)], by=A]$V1]
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2019-03-09
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2022-01-17
              相关资源
              最近更新 更多