如何用sapply传入双参数实现多变量分组加权两样本t检验?
多变量分组加权两样本t检验实现方案
问题描述
原代码可实现按carb分组对disp变量执行加权两样本t检验(以am为分组依据),但扩展到多变量(如cyl、drat、disp)时出现报错Error in var(x) : 'x' is NULL,需解决如何同时传入分组数据集与变量列表,并输出结构化结果表格的问题。
原可运行代码
library(tidyverse) library(weights) df_list <- split(mtcars, mtcars$carb) multiple_wt_ttest <- function(df) { ttest = wtd.t.test(x=subset(df, am == 0)$disp, y=subset(df, am == 1)$disp, weight=subset(df, am == 0)$wt, weighty=subset(df, am == 1)$wt, samedata=FALSE) out <<- ttest[2] } store <- do.call(rbind, sapply(df_list, multiple_wt_ttest))
报错的修改代码
library(tidyverse) library(weights) df_list <- split(mtcars, mtcars$carb) var_list <- list("cyl","drat","disp") multiple_wt_ttest <- function(df,var) { ttest = wtd.t.test(x=subset(df, am == 0)$var, y=subset(df, am == 1)$var, weight=subset(df, am == 0)$wt, weighty=subset(df, am == 1)$wt, samedata=FALSE) out <<- ttest[2] } store <- do.call(rbind, sapply(df_list,var=var_list, multiple_wt_ttest))
问题分析
- 变量引用错误:
$var无法识别字符串形式的变量名,需改用[[var]]来解析字符串变量。 - 迭代参数传递问题:
sapply仅支持单输入迭代,无法同时传入分组数据集和变量列表,需用嵌套迭代或组合迭代的方式处理。 - 全局变量副作用:使用
out <<-修改全局变量不规范,应让函数直接返回结果,避免意外副作用。 - 空组未处理:部分
carb分组下某am组可能无数据,直接运行检验会报错,需添加判断跳过此类情况。
解决方案
方案一:嵌套迭代(基于purrr)
利用tidyverse中的purrr包实现嵌套迭代,自动合并结果:
library(tidyverse) library(weights) # 修正后的检验函数:直接返回结构化结果 multiple_wt_ttest <- function(df, var) { # 提取两组数据 group0 <- df %>% filter(am == 0) group1 <- df %>% filter(am == 1) # 跳过空组情况 if(nrow(group0) == 0 || nrow(group1) == 0) { return(tibble(var = var, carb = unique(df$carb), statistic = NA, p_value = NA)) } # 执行加权t检验 ttest_result <- wtd.t.test(x = group0[[var]], y = group1[[var]], weight = group0$wt, weighty = group1$wt, samedata = FALSE) # 整理结果 tibble( var = var, carb = unique(df$carb), statistic = ttest_result$coefficients[1], p_value = ttest_result$coefficients[2] ) } # 定义分组和变量列表 carb_groups <- split(mtcars, mtcars$carb) var_list <- c("cyl", "drat", "disp") # 嵌套迭代:先遍历变量,再遍历每个carb分组 results <- map_dfr(var_list, function(var) { map_dfr(carb_groups, ~multiple_wt_ttest(.x, var)) }) # 查看最终结果 print(results)
方案二:组合迭代(基于expand.grid)
先生成所有carb值与变量的组合,再逐组执行检验:
library(tidyverse) library(weights) # 定义检验函数,直接接收carb值和变量名 multiple_wt_ttest <- function(carb_val, var, data = mtcars) { df <- data %>% filter(carb == carb_val) group0 <- df %>% filter(am == 0) group1 <- df %>% filter(am == 1) if(nrow(group0) == 0 || nrow(group1) == 0) { return(tibble(var = var, carb = carb_val, statistic = NA, p_value = NA)) } ttest_result <- wtd.t.test(x = group0[[var]], y = group1[[var]], weight = group0$wt, weighty = group1$wt, samedata = FALSE) tibble( var = var, carb = carb_val, statistic = ttest_result$coefficients[1], p_value = ttest_result$coefficients[2] ) } # 生成所有检验组合 test_combinations <- expand.grid( carb_val = unique(mtcars$carb), var = c("cyl", "drat", "disp"), stringsAsFactors = FALSE ) # 逐组合执行检验并合并结果 results <- pmap_dfr(test_combinations, multiple_wt_ttest) print(results)
关键改进点
- 使用
[[var]]正确解析字符串形式的变量名,替代无效的$var写法。 - 移除全局变量,让函数直接返回整理好的
tibble,避免副作用。 - 添加空组判断,防止因某分组下无数据导致的报错。
- 利用
map_dfr/pmap_dfr自动合并结果,比do.call(rbind, ...)更简洁稳定。 - 结果中保留
var(待检验变量)和carb(分组)信息,便于后续分析。
内容的提问来源于stack exchange,提问作者flâneur
相关产品推荐
相关产品推荐

