dplyr filter:获取具有最小变量的行,但仅获取第一个if多个最小值

Fel*_*x S 66 r dplyr

我希望使用一种分组过滤器dplyr,在每个组中只返回具有最小变量值的行x.

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

这是一个例子:

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))
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

使用ddply,我会以这种方式接近任务:

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

......有效:

  A x           y
1 A 1 -1.04584335
2 B 2  0.79600971
3 C 5 -0.08655151
Run Code Online (Sandbox Code Playgroud)

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

tal*_*lat 92

更新

使用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
Run Code Online (Sandbox Code Playgroud)

原始答案

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

group_by(df, A) %>% 
  filter(x == min(x)) %>% 
  filter(1:n() == 1)
Run Code Online (Sandbox Code Playgroud)

  • 我发现`do(head)`更容易阅读,`df%>%group_by(A)%>%filter(x == min(x))%>%do(head(.,1))` (3认同)

Fel*_*x S 35

只是为了完整性:这是最终dplyr解决方案,源自@hadley和@Arun的评论:

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


Aru*_*run 14

对于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]
Run Code Online (Sandbox Code Playgroud)


jun*_*kka 6

这可以通过row_number结合使用来实现group_byrow_number通过不仅通过值而且还通过向量中的相对顺序分配等级来处理关系。获取每个组的第一行的最小值为x

df.g <- group_by(df, A)
filter(df.g, row_number(x) == 1)
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅关于窗口函数的 dplyr小插图


Ben*_*ude 6

dplyr提供slice_min函数,它可以完成参数的工作with_ties = FALSE

library(dplyr)

df %>% 
  group_by(A) %>% 
  slice_min(x, with_ties = FALSE)
Run Code Online (Sandbox Code Playgroud)

输出 :

# 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 
Run Code Online (Sandbox Code Playgroud)