2つのデータフレームをマージし、そのうちの1つの元の行の順序を維持します(以下の例のdf.2
)。
以下にサンプルデータを示します(class
列のすべての値は両方のデータフレームで定義されています)。
df.1 <- data.frame(class = c(1, 2, 3), prob = c(0.5, 0.7, 0.3))
df.2 <- data.frame(object = c('A', 'B', 'D', 'F', 'C'), class = c(2, 1, 2, 3, 1))
私が行った場合:
merge(df.2, df.1)
出力は次のとおりです。
class object prob
1 1 B 0.5
2 1 C 0.5
3 2 A 0.7
4 2 D 0.7
5 3 F 0.3
sort = FALSE
を追加した場合:
merge(df.2, df.1, sort = F)
結果は次のとおりです。
class object prob
1 2 A 0.7
2 2 D 0.7
3 1 B 0.5
4 1 C 0.5
5 3 F 0.3
しかし、私が望むのは:
class object prob
1 2 A 0.7
2 1 B 0.5
3 2 D 0.7
4 3 F 0.3
5 1 C 0.5
Plyrパッケージのjoin関数を確認してください。マージに似ていますが、データセットの1つの行の順序を維持できます。全体として、マージよりも柔軟性があります。
サンプルデータを使用して、次のようにjoin
を使用します。
> join(df.2,df.1)
Joining by: class
object class prob
1 A 2 0.7
2 B 1 0.5
3 D 2 0.7
4 F 3 0.3
5 C 1 0.5
行の順序を維持するためのマージ関数の修正について説明するリンクがいくつかあります。
http://www.r-statistics.com/2012/01/merging-two-data-frame-objects-while-preserving-the-rows-order/
Df.2の行番号を与える変数を作成するだけです。次に、データをマージしたら、この変数に従って新しいデータセットを並べ替えます。以下に例を示します。
df.1<-data.frame(class=c(1,2,3), prob=c(0.5,0.7,0.3))
df.2<-data.frame(object=c('A','B','D','F','C'), class=c(2,1,2,3,1))
df.2$id <- 1:nrow(df.2)
out <- merge(df.2,df.1, by = "class")
out[order(out$id), ]
data.table v1.9.5 + から、次のことができます。
require(data.table) # v1.9.5+
setDT(df.1)[df.2, on="class"]
df.1
の各行に対してdf.2
の一致する行を見つけ、対応する列を抽出することにより、列class
で結合を実行します。
また、inner_join
関数は、Hadleyのdplyr
パッケージに含まれています(plyr
の次の反復)。最初のデータセットの行順序を保持します。目的のソリューションとのわずかな違いは、最初のデータセットの元の列の順序も保持することです。したがって、必ずしもマージに使用した列を最初の位置に配置するとは限りません。
上記の例を使用すると、inner_join
結果は次のようになります。
inner_join(df.2,df.1)
Joining by: "class"
object class prob
1 A 2 0.7
2 B 1 0.5
3 D 2 0.7
4 F 3 0.3
5 C 1 0.5
完全を期すために、joinを更新すると、元の行の順序も保持されます。追加する列が数個しかない場合、これは Arunのdata.table
answer の代わりになる可能性があります。
library(data.table)
setDT(df.2)[df.1, on = "class", prob := i.prob][]
object class prob 1: A 2 0.7 2: B 1 0.5 3: D 2 0.7 4: F 3 0.3 5: C 1 0.5
ここで、df.2
はdf.1
に右結合され、df.1
の一致する行からコピーされる新しい列prob
を取得します。
受け入れられた回答 は、merge
を使用するときに順序を維持するための手動の方法を提案します。これは、ほとんどの場合に機能しますが、不必要な手動作業を必要とします。この解決策は ソートせずにddply()する方法? の裏にあります。これは、順序を保持する問題を処理しますが、分割適用結合のコンテキストで:
これはしばらく前にplyrメーリングリストに登場しました(@kohskeも同様です)。これは、Peter Meilstrupが限られた場合に提供するソリューションです。
#Peter's version used a function gensym to
# create the col name, but I couldn't track down
# what package it was in.
keeping.order <- function(data, fn, ...) {
col <- ".sortColumn"
data[,col] <- 1:nrow(data)
out <- fn(data, ...)
if (!col %in% colnames(out)) stop("Ordering column not preserved by function")
out <- out[order(out[,col]),]
out[,col] <- NULL
out
}
したがって、この汎用keeping.order
関数を使用して、merge
呼び出しの元の行の順序を維持できます。
df.1<-data.frame(class=c(1,2,3), prob=c(0.5,0.7,0.3))
df.2<-data.frame(object=c('A','B','D','F','C'), class=c(2,1,2,3,1))
keeping.order(df.2, merge, y=df.1, by = "class")
リクエストに応じて、どちらが得られますか:
> keeping.order(df.2, merge, y=df.1, by = "class")
class object id prob
3 2 A 1 0.7
1 1 B 2 0.5
4 2 D 3 0.7
5 3 F 4 0.3
2 1 C 5 0.5
したがって、keeping.order
は、受け入れられた回答のアプローチを効果的に自動化します。
この特定のケースでは、コンパクトな基本ソリューションとしてfactor
を使用できます。
df.2$prob = factor(df.2$class,labels=df.1$prob)
df.2
# object class prob
# 1 A 2 0.7
# 2 B 1 0.5
# 3 D 2 0.7
# 4 F 3 0.3
# 5 C 1 0.5
一般的な解決策ではありませんが、次の場合に機能します:
left_join
1は交渉できません。残りは私たちにできることです。
df.3 <- df.2 # deal with 2.
df.1b <- df.1[order(df.1$class),] # deal with 3
df.1b <- df.1b[df.1$class %in% df.2$class,] # deal with 4.
df.3$prob = factor(df.3$class,labels=df.1b$prob)
df.3 <- df3[!is.na(df.3$prob),] # deal with 5. if you want an `inner join`
df.3$prob <- as.numeric(as.character(df.3$prob)) # deal with 6.
@PACのおかげで、次のようなものを思いつきました。
merge_sameord = function(x, y, ...) {
UseMethod('merge_sameord')
}
merge_sameord.data.frame = function(x, y, ...) {
rstr = paste(sample(c(0:9, letters, LETTERS), 12, replace=TRUE), collapse='')
x[, rstr] = 1:nrow(x)
res = merge(x, y, all.x=TRUE, sort=FALSE, ...)
res = res[order(res[, rstr]), ]
res[, rstr] = NULL
res
}
これは、最初のデータフレームの順序を保持し、マージされたデータフレームの行数が最初のデータフレームと同じになることを前提としています。余分な列のないきれいなデータフレームが得られます。
単純なサブセットが行ういくつかのユースケースがあります。
_# Use the key variable as row.names
row.names(df.1) = df.1$key
# Sort df.1 so that it's rows match df.2
df.3 = df.1[df.2$key, ]
# Create a data.frame with cariables from df.1 and (the sorted) df.2
df.4 = cbind(df.1, df.3)
_
このコードはdf.2とその順序を保持し、df.1からの一致するデータのみを追加します
変数を1つだけ追加する場合、cbind()
は不要です。
_row.names(df.1) = df.1$key
df.2$data = df.1[df.2$key, "data"]
_