dplyr filter:获取具有最小variables的行,但只有第一个如果多个最小值
我想用dplyr
做一个分组filter,在每个组中只有那个返回variablesx
的最小值的行。
我的问题是:正如所料,在多重最小值的情况下返回所有具有最小值的行。 但就我而言,如果存在多个最小值, 我只想要第一行 。
这是一个例子:
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 xy 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 xy 1 A 1 -1.04584335 2 B 2 0.79600971 3 C 5 -0.08655151
问:在dplyr中有没有办法解决这个问题? (由于速度原因)
更新
在dplyr> = 0.3的情况下,您可以结合使用slice
函数which.min
,这将是我最喜欢的任务:
df %>% group_by(A) %>% slice(which.min(x)) #Source: local data frame [3 x 3] #Groups: A # # A xy #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)
只是为了完整:这是最终的dplyr
解决scheme,来自@hadley和@Arun的评论:
library(dplyr) df.g <- group_by(df, A) filter(df.g, rank(x, ties.method="first")==1)
对于那些可能感兴趣的人来说,这是一个data.table
解决scheme。
# 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]
这可以通过使用row_number
与group_by
组合来完成。 row_number
通过不仅通过值而且通过向量内的相对顺序分配等级来处理关系。 要得到每个组的最小值为x
的第一行:
df.g <- group_by(df, A) filter(df.g, row_number(x) == 1)
有关更多信息,请参阅窗口函数上的dplyr 小插曲 。
我喜欢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
另一种方法来做到这一点:
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))
结果:
ab 1 1 -0.8356286 2 2 -2.2146999
也可以很容易地适应每个组获得最大价值的行。