R4.2.0运行自定义Beta_NTI函数报条件长度大于1错误咨询
问题背景
在R 4.2.0版本中定义了用于计算加权betaNTI的Beta_NTI函数,相同代码在R 4.1.0版本可正常运行,在R4.2.0中执行调用命令时抛出错误。
- 原函数代码:
Beta_NTI<-function(phylo,comun,beta.reps=999){ require(picante) match.phylo.comun = match.phylo.data(phylo, t(comun)) beta.mntd.weighted = as.matrix(comdistnt(t(match.phylo.comun$data),cophenetic(match.phylo.comun$phy),abundance.weighted=T)) rand.weighted.bMNTD.comp = array(c(-999),dim=c(ncol(match.phylo.comun$data),ncol(match.phylo.comun$data),beta.reps)) for (rep in 1:beta.reps) { rand.weighted.bMNTD.comp[,,rep] = as.matrix(comdistnt(t(match.phylo.comun$data),taxaShuffle(cophenetic(match.phylo.comun$phy)),abundance.weighted=T,exclude.conspecifics = F)) print(c(date(),rep)) } weighted.bNTI = matrix(c(NA),nrow=ncol(match.phylo.comun$data),ncol=ncol(match.phylo.comun$data)) for(columns in 1:(ncol(match.phylo.comun$data)-1)) { for(rows in (columns+1):ncol(match.phylo.comun$data)) { rand.vals = rand.weighted.bMNTD.comp[rows,columns,]; weighted.bNTI[rows,columns] = (beta.mntd.weighted[rows,columns] - mean(rand.vals)) / sd(rand.vals) rm("rand.vals") } } rownames(weighted.bNTI) = colnames(match.phylo.comun$data); colnames(weighted.bNTI) = colnames(match.phylo.comun$data); return(as.dist(weighted.bNTI)) }
- 调用命令:
Beta_NTI(bac_tree,t(bac)) - 报错信息:
Error in if (dataclass == "data.frame") { : the condition has length > 1 - 输入参数说明:
bac_tree为系统发育树对象,bac为OTU表,列名为样本ID、行名为OTU编号。
报错原因
R 4.2.0版本调整了if语句的校验规则:R4.1.0及更早版本中,若if的判断条件为长度大于1的逻辑向量,会默认取第一个元素执行判断,仅输出警告;R4.2.0及之后版本不再保留该兼容逻辑,只要判断条件长度不为1就会直接抛出错误。
本次报错的触发逻辑是:
- 多数用户读取OTU表时会用tidyverse包的read_*函数,读入的
bac是tbl_df(tibble)类型,该类型的class属性为长度3的向量c("tbl_df","tbl","data.frame"),而非基础data.frame的长度1的class值"data.frame"。 - picante包内部的类型判断语句
if (dataclass == "data.frame")直接拿多长度的class向量做相等判断,得到长度大于1的逻辑向量,在R4.2.0中直接触发报错。 - 存在冗余转置问题:函数内部已经对输入的
comun参数做了一次转置来匹配match.phylo.data的格式要求,调用时提前对bac做转置属于多余操作,会放大数据类型异常的概率。
修复方案
按以下步骤调整即可正常运行:
- 去掉调用时的冗余转置,直接传入原始OTU表,调用命令改为:
Beta_NTI(bac_tree, bac) - 在函数内强制将匹配后的群落数据转为基础data.frame格式,消除多类属性的影响,修改后的完整函数代码如下:
Beta_NTI<-function(phylo,comun,beta.reps=999){ require(picante) match.phylo.comun = match.phylo.data(phylo, t(comun)) # 强制转换为基础data.frame,避免tibble等数据类型导致的判断报错 match.phylo.comun$data <- as.data.frame(match.phylo.comun$data) beta.mntd.weighted = as.matrix(comdistnt(t(match.phylo.comun$data),cophenetic(match.phylo.comun$phy),abundance.weighted=T)) rand.weighted.bMNTD.comp = array(c(-999),dim=c(ncol(match.phylo.comun$data),ncol(match.phylo.comun$data),beta.reps)) for (rep in 1:beta.reps) { rand.weighted.bMNTD.comp[,,rep] = as.matrix(comdistnt(t(match.phylo.comun$data),taxaShuffle(cophenetic(match.phylo.comun$phy)),abundance.weighted=T,exclude.conspecifics = F)) print(c(date(),rep)) } weighted.bNTI = matrix(c(NA),nrow=ncol(match.phylo.comun$data),ncol=ncol(match.phylo.comun$data)) for(columns in 1:(ncol(match.phylo.comun$data)-1)) { for(rows in (columns+1):ncol(match.phylo.comun$data)) { rand.vals = rand.weighted.bMNTD.comp[rows,columns,]; weighted.bNTI[rows,columns] = (beta.mntd.weighted[rows,columns] - mean(rand.vals)) / sd(rand.vals) rm("rand.vals") } } rownames(weighted.bNTI) = colnames(match.phylo.comun$data); colnames(weighted.bNTI) = colnames(match.phylo.comun$data); return(as.dist(weighted.bNTI)) }
- (可选稳妥操作)传参前可将OTU表强制转换为基础矩阵格式,进一步规避数据类型问题:
bac <- as.matrix(bac) # 再执行函数调用 bNTI_res <- Beta_NTI(bac_tree, bac)
内容的提问来源于stack exchange,提问作者K J
相关产品推荐
相关产品推荐

