基于data.table高效计算系统发育世代与进化枝内距离统计的方法求助
高效计算各世代进化枝内符合距离阈值的类群对统计量
问题背景
我有4个系统发育树的分类单元(taxa),将系统发育树划分为不同“世代”,用来确定每个世代下的进化枝(clades)。示例数据如下:
library(data.table) clades = data.table(generation = rep(c("g0", "g4"), each = 4), taxa = rep(c(LETTERS[1:4]), times = 2), clade = c(1:4, 1, 1, 2, 2) )
- 世代g0:所有分类单元彼此独立,每个taxa对应单独的进化枝
- 世代g4:A与B同属进化枝1,C与D同属进化枝2
同时我存储了各分类单元间的地理距离,采用长格式存储:
distance = data.table( row = c("A", "A", "B", "A", "B", "C"), col = c("B", "C", "C", "D", "D", "D"), value = c(1.41, 5.65, 5.83, 5.83, 5.65, 1.41) )
需求
需要高效计算每个世代、每个进化枝内:
- 距离小于阈值(本示例阈值为2)的类群对数量(分子)
- 该进化枝内的总类群比对数(分母)
进而得到类群距离符合阈值的概率。
先给距离数据添加阈值标记列:
distance$cut = distance$value < 2
本示例的预期结果如下:
result = data.table(generation = c("g0", "g0", "g0", "g0", "g4", "g4"), clade = c(1, 2, 3, 4, 1, 2), numerator = c(0, 0, 0, 0, 1, 1), denominator = c(0, 0, 0, 0, 1, 1))
现有问题
我已通过*apply系列函数实现功能,但效率极低,无法支持大规模数据处理,现寻求高效实现方案。原实现代码:
generations = unique(clades$generation) output = lapply(generations, function(g) { generation_df = clades[clades$generation == g] clade_sets <- unique(generation_df$clade) clade_result <- sapply(clade_sets, function(cs) { clade_taxa = generation_df$taxa[generation_df$clade == cs] trait = distance$trait[distance$row %in% clade_taxa & distance$col %in% clade_taxa] if (length(trait) >= 1) { numerator = sum(trait) denominator = length(trait) } else { numerator = 0 denominator = 0 } list(numerator = numerator, denominator = denominator) }) # Combine clade result with generation and clade information data.frame( generation = g, clade = clade_sets, numerator = unlist(clade_result[1, ]), denominator = unlist(clade_result[2, ]), stringsAsFactors = FALSE ) }) dplyr::bind_rows(output)
高效实现方案
使用data.table的向量化连接与分组操作,完全避免循环,大幅提升大数据量下的处理效率:
library(data.table) # 原始数据初始化 clades = data.table(generation = rep(c("g0", "g4"), each = 4), taxa = rep(c(LETTERS[1:4]), times = 2), clade = c(1:4, 1, 1, 2, 2) ) distance = data.table( row = c("A", "A", "B", "A", "B", "C"), col = c("B", "C", "C", "D", "D", "D"), value = c(1.41, 5.65, 5.83, 5.83, 5.65, 1.41) ) # 添加距离阈值标记 distance[, cut := value < 2] # 关联每个配对的row和col对应的世代与进化枝信息 distance_clade = distance[clades, on = .(row = taxa), nomatch = 0, .(generation, clade_row = clade, row, col, cut)] distance_clade = distance_clade[clades, on = .(generation, col = taxa), nomatch = 0, .(generation, clade, cut)] # 筛选出同一进化枝内的配对 distance_clade = distance_clade[clade_row == clade] # 按世代和进化枝分组统计 stats = distance_clade[, .(numerator = sum(cut), denominator = .N), by = .(generation, clade)] # 补充无配对的进化枝并填充0 full_result = unique(clades[, .(generation, clade)])[stats, on = .(generation, clade)] full_result[, `:=`(numerator = fifelse(is.na(numerator), 0, numerator), denominator = fifelse(is.na(denominator), 0, denominator))] # 输出结果 full_result
方案优势
- 向量化操作:全程使用
data.table的向量化接口,避免循环带来的性能损耗 - 高效连接:通过键连接一次性关联所有配对的进化枝信息,比逐次筛选快得多
- 完整结果:自动补充无配对的进化枝,保证结果与预期完全一致
- 可扩展性:处理百万级数据时,性能远优于
apply系列函数
内容的提问来源于stack exchange,提问作者SamPassmore
相关产品推荐
相关产品推荐

