昨晚回答这个问题data.frame
,我花了一个小时试图找到一个没有在 for 循环中增长的解决方案,但没有任何成功,所以我很好奇是否有更好的方法来解决这个问题。
问题的一般情况归结为:
- 合并两个
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)
)
}
对于 is 的条目,输出应该看起来像sql
INNER JOIN
两个 data.frames 中的isMatch
一个TRUE
。我试图构建这两个data.frames
,以便在另一个中可以有 0 个或多个匹配项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
first 的尺寸,因为我不知道最终需要多少行。
我相信我将来会想出这个一般形式的问题。那么解决此类问题的正确方法是什么?