R语言多分组下lapply调用自定义随机化函数的正确性验证
问题说明
在数据框df中,已构建自定义函数f,用于计算x.sample与y.sample的相关系数。当前需求为执行999次随机化,针对4个sp分组分别计算每次随机化得到的per(即随机化场景下的预期相关系数)。需要验证现有代码中lapply的写法是否正确,是否确实调用了per的计算逻辑,确认代码是针对4个sp分组计算per相关系数,而非执行其他计算逻辑。
待验证代码
set.seed(111) library(truncnorm) x <- rtruncnorm(n = 288,a = 0,b = 10,mean = 5,sd = 2) v <- rtruncnorm(n = 288,a = 0,b = 10,mean = 5,sd = 2) y <- ((v/x^2) - (1/x)) sp <- rep(c("A","B","C","D"), each = 72) df <- data.frame(v,x,y,sp) library(data.table) setDT(df) # 自定义计算函数 f <- function(x,v) {x.sample <- sample(x, length(x), replace=T) y.sample <- (v/x.sample^2) - (1/x.sample) per <- cor(y.sample, x.sample)} set.seed(1234) # 每个物种生成999次随机化结果 result = rbindlist( lapply(1:999, \(i) df[,.(est = f(x,v)), sp][, i:=i]) )
简单验证方法
- 校验结果维度:代码运行完成后执行
dim(result),正常返回值应该是3996行(999次迭代*4个分组)、3列(sp分组、est计算值、迭代编号i)。再执行table(result$sp, result$i),可以看到每个迭代编号i下,A/B/C/D四个分组各有1条记录,说明迭代和分组逻辑没有问题。 - 加校验逻辑调试函数入参:临时修改函数
f,加入入参长度校验和打印逻辑,不用跑满999次,只跑前2-3次迭代即可确认分组是否正确:
f <- function(x,v) { # 单个sp分组固定有72个样本,长度不对直接报错终止 stopifnot(length(x) == 72, length(v) ==72) x.sample <- sample(x, length(x), replace=T) y.sample <- (v/x.sample^2) - (1/x.sample) per <- cor(y.sample, x.sample) # 打印当前计算的样本量和结果,方便核对 message("当前分组样本量:", length(x), ",per计算结果:", round(per,4)) return(per) } # 只跑3次迭代测试 test_res <- rbindlist( lapply(1:3, \(i) df[,.(est = f(x,v)), sp][, i:=i]) )
运行后如果没有报错,且每次打印的样本量都是72,说明函数确实是在单个sp分组内被调用的。
- 手动计算对照结果:固定随机种子,单独提取单个分组手动计算,和代码输出结果比对。比如固定和原代码一致的种子1234,单独计算sp=A组第一次迭代的结果:
set.seed(1234) # 手动计算第一次迭代A组的per值 manual_cal <- df[sp=="A", f(x,v)] # 提取原代码结果中第一次迭代A组的est值 code_res <- result[i==1 & sp=="A", est] # 两个值完全一致则说明计算逻辑没有偏差 stopifnot(manual_cal == code_res)
补充说明:你当前写的代码逻辑本身是正确的,
df[,.(est = f(x,v)), sp]是data.table标准的按组计算语法,会自动按sp列拆分数据,把每个分组的x、v向量传入函数f计算,外层lapply负责循环999次、给每次结果标记迭代号,最后合并所有结果,完全匹配你的需求。
内容的提问来源于stack exchange,提问作者Rspacer
相关产品推荐
相关产品推荐

