无需依赖broom包的data.table逐行执行prop.test方案
不依赖broom的data.table逐行prop.test解决方案
需求背景
需要在data.table的每行中运行两样本比例检验(prop.test),并将检验结果(卡方值、p值、置信区间上下限)提取为新列,同时避免引入broom::tidy带来的额外依赖和性能损耗。
测试数据构造
首先生成用于测试的data.table,包含两组样本量(n1/n2)和成功数(x1/x2):
library(data.table) set.seed(123) DT <- data.table( n1 = sample(50:100, 10), x1 = sample(10:40, 10), n2 = sample(50:100, 10), x2 = sample(10:40, 10) )
方法一:data.table逐行分组处理
利用data.table的分组语法,按行分组后直接运行prop.test并提取所需结果:
DT[, c("chisq", "p_value", "ci_low", "ci_high") := { # 运行两样本比例检验,可根据需求调整correct参数 test_res <- prop.test(x = c(x1, x2), n = c(n1, n2), correct = FALSE) # 提取指定结果,注意索引对应htest对象的元素 list( test_res$statistic[[1]], # 提取卡方值(statistic是命名向量,取第一个元素) test_res$p.value, test_res$conf.int[[1]], # 置信区间下限 test_res$conf.int[[2]] # 置信区间上限 ) }, by = 1:nrow(DT)]
方法二:mapply批量处理(更高效)
对于大数据量,使用base::mapply批量处理每行数据,再将结果合并回原data.table,性能优于逐行分组:
# 批量运行prop.test并提取结果 test_results <- mapply( function(x1, x2, n1, n2) { res <- prop.test(x = c(x1, x2), n = c(n1, n2), correct = FALSE) list( chisq = res$statistic[[1]], p_value = res$p.value, ci_low = res$conf.int[[1]], ci_high = res$conf.int[[2]] ) }, DT$x1, DT$x2, DT$n1, DT$n2, SIMPLIFY = FALSE # 保持结果为列表格式 ) # 将结果列表转为data.table并合并 DT <- cbind(DT, rbindlist(test_results))
关键说明
- 避免unlist失败的原因:
prop.test返回的htest对象包含不同结构的元素(如命名向量、长度为2的区间向量),直接unlist会扁平化所有元素,无法精准提取目标值,因此需要直接索引对应元素。 - 参数调整:
prop.test的correct参数默认开启连续性修正,若样本量较大可设为FALSE以提升计算效率。 - 性能对比:两种方法均仅依赖
data.table和base R,无额外包依赖;mapply方案在处理10万+行数据时,速度显著优于broom::tidy的逐行处理方式。
结果验证(可选)
若需要验证结果准确性,可与broom::tidy的输出对比:
library(broom) DT_broom <- DT[, tidy(prop.test(c(x1,x2), c(n1,n2), correct=FALSE)), by=1:nrow(DT)] # 检查数值一致性 all.equal(DT$chisq, DT_broom$statistic) all.equal(DT$p_value, DT_broom$p.value) all.equal(DT$ci_low, DT_broom$conf.low) all.equal(DT$ci_high, DT_broom$conf.high)
内容的提问来源于stack exchange,提问作者dragon951
相关产品推荐
相关产品推荐

