/ / dplyrフィルター:最小の変数で行を取得しますが、複数の最小値がある場合は最初の行のみ-r、dplyr

dplyrフィルタ:最小限の変数で行を取得しますが、複数の最小値-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))

予想どおり、すべての最小値が返されます。

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

Q:dplyrでこれにアプローチする方法はありますか? (速度上の理由から)

回答:

回答№1は66

更新

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

元の回答

サンプルデータについては、2つを使用することも可能です filter お互いの後:

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

答え№2の27

完全を期すために:ここに「最後の dplyr @hadleyと@Arunのコメントから派生したソリューション:

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

回答№3の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]

答え№4の2

これは以下を使用して実現できます row_number と組み合わせ group_by. row_number 値だけでなく、ベクトル内の相対的な順序でもランクを割り当てることにより、タイを処理します。最小値を持つ各グループの最初の行を取得するには x

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

詳細については、dplyrを参照してください ウィンドウ関数のビネット.


回答№5の場合は0

私はそのシンプルさから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の場合は0

それを行う別の方法:

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

また、各グループの行を最大値で取得するように簡単に適合させることもできます。