昨夜この質問に答えdata.frame
て、 for ループで成長しない解決策を見つけるのにかなりの時間を費やしましたが、成功しませんでした。この問題に対処するより良い方法があるかどうか知りたいです。
問題の一般的なケースは次のようになります。
- 2つをマージ
data.frames
- いずれか
data.frame
のエントリは、他方に 0 個以上の一致するエントリを持つことができます。 - 両方で 1 つ以上の一致があるエントリのみを考慮します。
- 一致関数が複雑で、両方
data.frame
の sに複数の列が含まれている
具体的な例として、リンクされた質問と同様のデータを使用します。
genes <- data.frame(gene = letters[1:5],
chromosome = c(2,1,2,1,3),
start = c(100, 100, 500, 350, 321),
end = c(200, 200, 600, 400, 567))
markers <- data.frame(marker = 1:10,
chromosome = c(1, 1, 2, 2, 1, 3, 4, 3, 1, 2),
position = c(105, 300, 96, 206, 150, 400, 25, 300, 120, 700))
そして、複雑なマッチング関数:
# matching criteria, applies to a single entry from each data.frame
isMatch <- function(marker, gene) {
return(
marker$chromosome == gene$chromosome &
marker$postion >= (gene$start - 10) &
marker$postion <= (gene$end + 10)
)
}
が であるエントリの出力はsql
INNER JOIN
、2 つの data.frames の のようになります。もう一方に0個以上の一致があるように、2つを構築しようとしました。isMatch
TRUE
data.frames
data.frame
私が思いついた解決策は次のとおりです。
joined <- data.frame()
for (i in 1:nrow(genes)) {
# This repeated subsetting returns the same results as `isMatch` applied across
# the `markers` data.frame for each entry in `genes`.
matches <- markers[which(markers$chromosome == genes[i, "chromosome"]),]
matches <- matches[which(matches$pos >= (genes[i, "start"] - 10)),]
matches <- matches[which(matches$pos <= (genes[i, "end"] + 10)),]
# matches may now be 0 or more rows, which we want to repeat the gene for:
if(nrow(matches) != 0) {
joined <- rbind(joined, cbind(genes[i,], matches[,c("marker", "position")]))
}
}
結果を与える:
gene chromosome start end marker position
1 a 2 100 200 3 96
2 a 2 100 200 4 206
3 b 1 100 200 1 105
4 b 1 100 200 5 150
5 b 1 100 200 9 120
51 e 3 321 567 6 400
これは非常に醜く扱いにくい解決策ですが、私が試した他の方法はすべて失敗に終わりました。
- を使用すると
apply
、list
各要素が行列であることがわかりましたが、rbind
それらへの道はありませんでした。 joined
最終的に何行必要になるか分からないので、最初の次元を指定することはできません。
将来、この一般的な形式の問題を思いつくと思います。では、この種の問題を解決する正しい方法は何ですか?