R中匹配拓扑相同的系统发育树节点以计算平均分支长度
解决方案
方法1:节点唯一标识匹配法(最稳妥)
核心逻辑:拓扑相同的两棵树,每个节点对应的所有后代末梢标签集合是唯一且固定的,不受节点存储顺序影响,我们可以把这个集合转为字符串作为匹配主键,实现100%准确的节点匹配。
代码实现
# 加载所需包 library(ape) library(tidytree) library(dplyr) library(purrr) # 自定义函数:生成节点唯一匹配键 get_node_key <- function(tree, node) { # 末梢节点直接返回自身标签作为键 if (node <= ape::Ntip(tree)) { return(tree$tip.label[node]) } # 内部节点取所有后代末梢标签,排序后拼接为唯一键 descendant_tips <- ape::extract.clade(tree, node)$tip.label sort(descendant_tips) |> paste0(collapse = "|") } # 分别为两棵树的所有节点生成匹配键 t1_tbl <- tidytree::as_tibble(t1) |> mutate(node_key = map_chr(node, ~get_node_key(t1, .x))) t2_tbl <- tidytree::as_tibble(t2) |> mutate(node_key = map_chr(node, ~get_node_key(t2, .x))) # 按键匹配,计算分支长度平均值 match_result <- inner_join( t1_tbl |> select(node_key, label, bl_t1 = branch.length), t2_tbl |> select(node_key, bl_t2 = branch.length), by = "node_key" ) |> mutate(bl_avg = (bl_t1 + bl_t2)/2) # 如果需要生成平均分支长度的新系统发育树,直接用t1的拓扑赋值即可 avg_tree <- t1 avg_tree$edge.length <- match_result$bl_avg[match(t1_tbl$node_key, match_result$node_key)]
方法2:补全matchNodes的末梢匹配
phytools::matchNodes默认仅返回内部节点的匹配结果,没有包含末梢节点,因此你之前看不到末梢的对应关系,手动补全末梢匹配即可得到完整的节点对应表:
代码实现
# 1. 匹配内部节点 inner_node_match <- phytools::matchNodes(t1, t2, method = "descendants") colnames(inner_node_match) <- c("t1_node", "t2_node") # 2. 匹配末梢节点(按标签直接匹配) tip_node_match <- data.frame( t1_node = 1:ape::Ntip(t1), t2_node = match(t1$tip.label, t2$tip.label) ) # 3. 合并得到所有节点的匹配表 all_node_match <- rbind(tip_node_match, inner_node_match) # 4. 提取对应分支长度计算平均值 t1_bl <- t1$edge.length[match(all_node_match$t1_node, t1$edge[,2])] t2_bl <- t2$edge.length[match(all_node_match$t2_node, t2$edge[,2])] avg_bl <- (t1_bl + t2_bl)/2
内容的提问来源于stack exchange,提问作者dan
相关产品推荐
相关产品推荐

