在R循环中对数据框执行Shapiro检验时如何正确使用!!sym?
问题解决:R循环中计算配对差值的报错修正
错误原因
!!sym(i)是tidyverse专属的非标准求值语法,仅能在支持tidyeval的函数(如dplyr::summarise/mutate)中使用,with()函数不识别该语法,因此触发invalid argument type错误。此外,你的代码未考虑配对数据的ID对齐,直接用列索引相减可能导致差值匹配错误(若数据排序混乱)。
修正方案
以下提供两种可行的实现方式,均保证配对差值按ID正确计算:
方法1:基础R+宽格式转换(直观易读)
先将数据转为宽格式,让同一ID的A/B处理结果在同一行,再计算差值:
library(tidyverse) library(readxl) library(broom) # 需加载此包使用tidy()整理检验结果 # 读取数据 df <- read_excel(paste0(getwd(),"/Data.xlsm"), sheet="data") # 转换为宽格式:每个指标的A/B结果分列为两列 df_wide <- df %>% select(ID, Treatment, Effect, Intake, Temperature) %>% pivot_wider(names_from = Treatment, values_from = c(Effect, Intake, Temperature)) # 遍历指定列 for (i in c("Effect","Intake", "Temperature")){ # 计算配对差值(A - B,可根据需求改为B - A) mean_diff <- df_wide[[paste0(i, "_A")]] - df_wide[[paste0(i, "_B")]] # Shapiro正态性检验 s_test <- tidy(shapiro.test(mean_diff)) cat("\n=== ", i, "的Shapiro检验结果 ===\n") print(s_test) # 配对t检验 t_test <- tidy(t.test(mean_diff, paired = TRUE)) cat("\n=== ", i, "的配对t检验结果 ===\n") print(t_test) # 绘制差值直方图(直观判断正态性) p <- ggplot(data.frame(diff = mean_diff), aes(x = diff)) + geom_histogram(bins = 10, fill = "lightblue", color = "black") + labs(title = paste(i, "配对差值分布"), x = "差值(A-B)", y = "频数") + theme_minimal() print(p) }
方法2:tidyverse循环(无需转格式)
利用tidyeval语法在dplyr函数内处理,直接按ID分组计算差值:
library(tidyverse) library(readxl) library(broom) df <- read_excel(paste0(getwd(),"/Data.xlsm"), sheet="data") for (i in c("Effect","Intake", "Temperature")){ # 按ID分组,提取对应指标的A/B值并计算差值 mean_diff <- df %>% group_by(ID) %>% summarise(diff = !!sym(i)[Treatment == "A"] - !!sym(i)[Treatment == "B"]) %>% pull(diff) # 正态性检验与t检验 s_test <- tidy(shapiro.test(mean_diff)) t_test <- tidy(t.test(mean_diff, paired = TRUE)) cat("\n=== ", i, "统计结果 ===\n") print("Shapiro检验:") print(s_test) print("\n配对t检验:") print(t_test) # 绘制QQ图(更适合判断正态性) p <- ggplot(data.frame(diff = mean_diff), aes(sample = diff)) + geom_qq() + geom_qq_line(color = "red") + labs(title = paste(i, "差值QQ图"), subtitle = "偏离红线越远,正态性越差") + theme_minimal() print(p) }
关键注意点
- 配对数据必须按ID对齐计算差值,否则会出现逻辑错误;
broom::tidy()用于将检验结果转为结构化数据框,方便后续导出或查看;- 若只需判断正态性,除Shapiro检验外,QQ图/直方图的直观判断也很重要(尤其样本量较小时,Shapiro检验敏感度有限)。
内容的提问来源于stack exchange,提问作者JLit98
相关产品推荐
相关产品推荐

