【发布时间】:2015-04-01 20:44:24
【问题描述】:
这是一棵树。第一列是分支的标识符,其中0 是主干,L 是左侧的第一个分支,R 是右侧的第一个分支。 LL 是第二次分叉后最左边的分支,等等。变量length 包含每个分支的长度。
> tree
branch length
1 0 20
2 L 12
3 LL 19
4 R 19
5 RL 12
6 RLL 10
7 RLR 12
8 RR 17
tree = data.frame(branch = c("0","L", "LL", "R", "RL", "RLL", "RLR", "RR"), length=c(20,12,19,19,12,10,12,17))
tree$branch = as.character(tree$branch)
这是这棵树的图画
这是这棵树上的两个位置
posA = tree[4,]; posA$length = 12
posB = tree[6,]; posB$length = 3
位置由分支 ID 和到分支原点的距离(变量 length)给出(更多信息在编辑中)。
我编写了以下凌乱的distance 函数来计算树上任意两点之间的沿树枝的最短距离。 沿着树枝的最短距离可以理解为蚂蚁沿着树枝行走从另一个位置到达一个位置所需的最小距离。
distance = function(tree, pos1, pos2){
if (identical(pos1$branch, pos2$branch)){Dist=pos1$length-pos2$length;return(Dist)}
pos1path = strsplit(pos1$branch, "")[[1]]
if (pos1path[1]!="0") {pos1path = c("0", pos1path)}
pos2path = strsplit(pos2$branch, "")[[1]]
if (pos2path[1]!="0") {pos2path = c("0", pos2path)}
loop = 1:min(length(pos1path), length(pos2path))
loop = loop[-which(loop == 1)]
CommonTrace="included"; for (i in loop) {
if (pos1path[i] != pos2path[i]) {
CommonTrace = i-1; break
}
}
if(CommonTrace=="included"){
CommonTrace = min(length(pos1path), length(pos2path))
if (length(pos1path) > length(pos2path)) {
longerpos = pos1; shorterpos = pos2; longerpospath = pos1path
} else {
longerpos = pos2; shorterpos = pos1; longerpospath = pos2path
}
distToNode = 0
if ((CommonTrace+1) != length(longerpospath)){
for (i in (CommonTrace+1):(length(longerpospath)-1)){
distToNode = distToNode + tree$length[tree$branch == paste0(longerpospath[2:i], collapse='')]
}
}
Dist = distToNode + longerpos$length + (tree[tree$branch == shorterpos$branch,]$length-shorterpos$length)
if (identical(shorterpos, pos1)){Dist=-Dist}
return(Dist)
} else { # if they are sisterbranch
Dist=0
if((CommonTrace+1) != length(pos1path)){
for (i in (CommonTrace+1):(length(pos1path)-1)){
Dist = Dist + tree$length[tree$branch == paste0(pos1path[2:i], collapse='')]
}
}
if((CommonTrace+1) != length(pos2path)){
for (i in (CommonTrace+1):(length(pos2path)-1)){
Dist = Dist + tree$length[tree$branch == paste(pos2path[2:i], collapse='')]
}
}
Dist = Dist + pos1$length + pos2$length
return(Dist)
}
}
我认为该算法运行良好,但效率不高。注意重要的距离符号。仅当在“姐妹分支”上找不到两个位置时,此标志才有意义。只有当两个位置中的一个位于根和另一个位置之间的路上时,该符号才有意义。
distance(tree, posA, posB) # -22
然后我就这样遍历所有感兴趣的位置:
allpositions=rbind(tree, tree)
allpositions$length = c(1,5,8,2,2,3,5,6,7,8,2,3,1,2,5,6)
mat = matrix(-1, ncol=nrow(allpositions), nrow=nrow(allpositions))
for (i in 1:nrow(allpositions)){
for (j in 1:nrow(allpositions)){
posA = allpositions[i,]
posB = allpositions[j,]
mat[i,j] = distance(tree, posA, posB)
}
}
# 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
# 1 0 -24 -39 -21 -40 -53 -55 -44 -6 -27 -33 -22 -39 -52 -55 -44
# 2 24 0 -15 7 26 39 41 30 18 -3 -9 8 25 38 41 30
# 3 39 15 0 22 41 54 56 45 33 12 6 23 40 53 56 45
# 4 21 7 22 0 -19 -32 -34 -23 15 10 16 -1 -18 -31 -34 -23
# 5 40 26 41 19 0 -13 -15 8 34 29 35 18 1 -12 -15 8
# 6 53 39 54 32 13 0 8 21 47 42 48 31 14 1 8 21
# 7 55 41 56 34 15 8 0 23 49 44 50 33 16 7 0 23
# 8 44 30 45 23 8 21 23 0 38 33 39 22 7 20 23 0
# 9 6 -18 -33 -15 -34 -47 -49 -38 0 -21 -27 -16 -33 -46 -49 -38
# 10 27 3 -12 10 29 42 44 33 21 0 -6 11 28 41 44 33
# 11 33 9 -6 16 35 48 50 39 27 6 0 17 34 47 50 39
# 12 22 8 23 1 -18 -31 -33 -22 16 11 17 0 -17 -30 -33 -22
# 13 39 25 40 18 -1 -14 -16 7 33 28 34 17 0 -13 -16 7
# 14 52 38 53 31 12 -1 7 20 46 41 47 30 13 0 7 20
# 15 55 41 56 34 15 8 0 23 49 44 50 33 16 7 0 23
# 16 44 30 45 23 8 21 23 0 38 33 39 22 7 20 23 0
例如,让我们考虑对象allpositions 中的第一个和第三个位置。它们之间的距离是39(和-39),因为蚂蚁需要在0 分支上行走19 个单位,然后在L 分支上行走12 个单位,最后蚂蚁需要在8 个单位上行走在分支上LL。 19 + 12 + 8 = 39
问题是我有大约 20 棵非常大的树,大约有 50000 个位置,我想计算任意两个位置之间的距离。因此需要计算 20 * 50000^2 的距离。它需要永远!你能帮我改进我的代码吗?
编辑
如果还有什么不清楚的地方请告诉我
tree 是对树的描述。这棵树有某个length 的分支。分支的名称(变量:branch)表明了分支之间的关系。分支RL 是两个分支RLL 和RLR 的“父分支”,其中R 和L 代表左右。
allpositions 是一个 data.frame,其中每一行代表树上的一个独立位置。你可以想象松鼠的位置。该位置由两个信息定义。 1)松鼠站立的树枝(变量:branch)以及树枝起点到松鼠位置的距离(变量:length)。
三个例子
假设第一只松鼠位于分支RL(长度为12)上的位置(变量:length)8,第二只松鼠位于分支的位置(变量:length)2 RLL 或 RLR。两只松鼠之间的距离是12 - 8 + 2 = 6(或-6)。
假设第一只松鼠位于分支RL 上的位置(变量:length)8,第二只松鼠位于分支RR 的位置(变量:length)2。两只松鼠之间的距离是8 + 2 = 10(或-10)。
考虑第一只松鼠位于分支R(长度为19)上的位置(变量:length)8,第二只松鼠位于分支的位置(变量:length)2 RLL。知道那个分支RL的长度是12,两只松鼠之间的距离是19 - 8 + 12 + 2 = 25(或-25)。
【问题讨论】:
-
发布的代码和数据给了我:
Error in pos1$branch : $ operator is invalid for atomic vectors-- 请更新,以便成为可重现的示例。 -
您的
branch变量是字符向量吗?我认为这可能会导致问题。我添加了两行,以便清楚地了解如何构建tree对象。它解决了问题吗?感谢您的评论。 -
我刚刚复制了您发布的用于创建
tree的代码,复制了您的distance函数,并在运行distance(tree, 1, 2)时遇到了错误。 -
该函数接受参数
tree、pos1和pos2。尝试运行distance(tree, pos1, pos2)。我重新启动了 R,它仍然可以在我的计算机上运行。它对你的不起作用吗? -
哦,我假设
allpositions存储了索引,因为您使用它来索引mat。如果您有类似allpositions <- list(pos1, pos2)的东西,那么您的最后一段代码将无法工作(因为mat[i,j]将无法工作)。这就是让我失望的原因。你能更新最后一点,让它可以运行吗?这将涉及添加allpositions和初始化mat。
标签: r performance tree