R data.table过滤后系谱世代字段计算结果异常问题
data.table系谱世代计算异常的根因与解决方法
根因说明
该问题并非data.table的异常行为,是两个使用误区叠加导致的:
- 全量系谱表中个体ID恰好与行号完全对齐,导致你混淆了「按ID值匹配记录」和「按行号索引取数」的逻辑差异,之前的计算结果属于巧合正确
- data.table的
[操作符默认将数值型输入识别为行位置索引,而非列值匹配条件,和你之前使用data.frame的隐含使用习惯产生了冲突,过滤后表的行号与ID不再对齐,问题就直接暴露了
解决方法
- 方案1:使用data.table键匹配逻辑,从根源避免行号与ID混淆
提前给系谱表设置ID列为主键,所有匹配操作都基于主键完成,示例代码如下:library(data.table) # 给新系谱表设置主键 setkey(pedigree.new, id) # 初始化基础世代:无亲本的founder世代设为0 pedigree.new[is.na(sire) & is.na(dam), gen := 0] # 迭代计算后代世代,按主键匹配亲本的世代值 while(any(is.na(pedigree.new$gen))) { pedigree.new[is.na(gen), `:=`( sire_gen = pedigree.new[as.character(sire), gen], dam_gen = pedigree.new[as.character(dam), gen] )][is.na(gen), gen := pmax(sire_gen, dam_gen) + 1] } # 删除临时辅助列 pedigree.new[, c("sire_gen", "dam_gen") := NULL] - 方案2:保留原有match逻辑,显式声明匹配规则
如果你不想修改原有计算逻辑,只需要显式指定用id列做匹配,不要将match返回的索引当成ID值使用即可:all_id <- pedigree.new$id # 初始化世代 pedigree.new$gen <- ifelse(is.na(pedigree.new$sire) & is.na(pedigree.new$dam), 0, NA) # 迭代更新后代世代 while(any(is.na(pedigree.new$gen))) { na_idx <- which(is.na(pedigree.new$gen)) for (i in na_idx) { sire_p <- match(pedigree.new$sire[i], all_id) dam_p <- match(pedigree.new$dam[i], all_id) pedigree.new$gen[i] <- max(pedigree.new$gen[sire_p], pedigree.new$gen[dam_p]) + 1 } }
验证方法
执行完成后输出pedigree.new[, .(id, gen)],确认ID为13、19、23的亲本世代为0,3个后代世代为1即修复完成。
内容的提问来源于stack exchange,提问作者Rob
相关产品推荐
相关产品推荐

