特定の順序のベクトルに従ってデータフレーム行を順序付け


158

以下の短い例で実装したもののように、「ターゲット」ベクトルに従ってデータフレームの行が確実に順序付けられるようにする簡単な方法はありますか?

df <- data.frame(name = letters[1:4], value = c(rep(TRUE, 2), rep(FALSE, 2)))

df
#   name value
# 1    a  TRUE
# 2    b  TRUE
# 3    c FALSE
# 4    d FALSE

target <- c("b", "c", "a", "d")

これはどういうわけか、仕事を成し遂げるには少し複雑すぎるようです:

idx <- sapply(target, function(x) {
    which(df$name == x)
})
df <- df[idx,]
rownames(df) <- NULL

df 
#   name value
# 1    b  TRUE
# 2    c FALSE
# 3    a  TRUE
# 4    d FALSE

回答:


232

試してくださいmatch

df <- data.frame(name=letters[1:4], value=c(rep(TRUE, 2), rep(FALSE, 2)))
target <- c("b", "c", "a", "d")
df[match(target, df$name),]

  name value
2    b  TRUE
3    c FALSE
1    a  TRUE
4    d FALSE

target同じ要素が含まれている限り、機能しますdf$name含み、どちらにも重複する値が含まれていない、機能します。

から?match

match returns a vector of the positions of (first) matches of its first argument 
in its second.

したがってmatchtargetの要素に一致する行番号を見つけ、dfその順序で返します。


すごい、それはもっとそれに似ていて、まさに私が探していたものです!
どうも

1
1つの質問、一致させたい列に繰り返し値がある場合はどうなりますか?のようにb,c,a,d,b,c,a,d。試しましたmatchがうまくいきません。
Yulong 2013

@ユロン:発砲する前に重複が削除されていることを明示的に確認する必要があると思いますmatch()。何頭に浮かぶことでduplicated()unique()他の人を捨てながら、所望の要素を「続ける」ことや他のいくつかのカスタム・ルーチン。HTH
Rappster 2013年

@エドワードそれは素晴らしい解決策です。ただし、インデックスも変更されます。それらを昇順(1、2、3、4)に保つにはどうすればよいですか?
Hasan Iqbal 2015年

2
ないでください、それはクリーンな方法ですが、あなたはDFで重複している場合のみ、「ベース」の機能で、これは動作するはずです:df <- data.frame(name=letters[c(1:4, 1:4)], value=c(rep(TRUE, 2), rep(FALSE, 2),rep(TRUE, 2), rep(FALSE, 2) )) target <- c("b", "c", "a", "d") df[order(unlist(sapply(df$name, function(x) which(target == x)))),]
エリカFary

21

データを照合する必要***_join があるdplyrときはいつでも使用することを好みます。このための1つの可能な試み

left_join(data.frame(name=target),df,by="name")

の入力には***_joinrequire tblsまたはdata.frameが必要です。


うん、* _ join関数dplyrは本当にいいです。これらも今ではよく
使う

この場合、data.frame()が因子に変換されないように、ターゲットの順序をティブルとして宣言することをお勧めします。target <- tibble(name = c("b", "c", "a", "d"))
イラクサ2017

2
パイプ構文を使用する場合:df %>% right_join(tibble(name = target), by = "name")
Frank

18

この方法は少し異なり、以前の回答よりも少し柔軟性がありました。順序付けられた要素にすることでarrange、などでうまく使えます。gdataパッケージのreorder.factorを使用しました。

df <- data.frame(name=letters[1:4], value=c(rep(TRUE, 2), rep(FALSE, 2)))
target <- c("b", "c", "a", "d")

require(gdata)
df$name <- reorder.factor(df$name, new.order=target)

次に、現在注文されているという事実を使用します。

require(dplyr)
df %>%
  arrange(name)
    name value
1    b  TRUE
2    c FALSE
3    a  TRUE
4    d FALSE

元の(アルファベット順)の順序に戻したい場合は、を使用as.character()して元の状態に戻します。


2
誰かがこれのdata.tableバージョンを知っていますか?
Reilstein、2016

2
@ライルシュタインsetDT(df)[ , name := factor(name, levels = target)]。次に、ここの2つのdata.table回答を参照してください
Henrik

4

に基づいて因子レベルを調整しtargetて使用することができますarrange

library(dplyr)
df %>% arrange(factor(name, levels = target))

#  name value
#1    b  TRUE
#2    c FALSE
#3    a  TRUE
#4    d FALSE

またはorderそれを使ってslice

df %>% slice(order(factor(name, levels = target)))

2
最高のソリューションIMO
stevec

1
私にとって最良かつ最も簡単なソリューション。
Matt_B

0

あなたが任意のライブラリを使用しないと、あなたのデータで再発を持っている場合は、使用することができるwhichsapply同様。

new_order <- sapply(target, function(x,df){which(df$name == x)}, df=df)
df        <- df[new_order,]
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.