一个 R 函数,用于执行 t 检验以整齐地比较均值和输出结果

An R function to perform t-test to compare means and output result in a tidy way

我有具有以下结构的数据框(一个字符和 3 个数字),但数字列的名称各不相同:

structure(list(treatment = c("product", "product", "product", "product", "product", "control", "control", "control", "control", "control"), t0 = 1:10, t1 = c(1, 3, 5, 7, 9, 11, 13, 15, 17, 19), t2 = c(1, 4, 7, 10, 13, 16, 19, 22, 25, 28)), class = c("tbl_df",  "tbl", "data.frame"), row.names = c(NA, -10L))

 treatment    t0    t1    t2
   <chr>     <int> <dbl> <dbl>
 1 product       1     1     1
 2 product       2     3     4
 3 product       3     5     7
 4 product       4     7    10
 5 product       5     9    13
 6 control       6    11    16
 7 control       7    13    19
 8 control       8    15    22
 9 control       9    17    25
10 control      10    19    28

我想设置一个函数来执行 t 检验和比较均值(t1 vs t0 和 t2 vs t0)。然而,这个函数需要能够在我拥有的所有数据框中工作,也就是说,包括那些数字列不被称为 t0、t1、t2 的数据框。所以我认为它可能通过调用函数内的列号来工作,但 t.test 函数似乎不接受。此外,以整洁的方式获得函数的结果会很好。最后,它会像这样工作:

my_ttest_func(df)

 t1_t0        t     estimate   p_value
  <chr>     <dbl>    <dbl>     <dbl>
1 product   5.94     7.19    0.0000104
2 control   1.98     2.32    0.0327  

 t2_t0        t     estimate  p_value
  <chr>     <dbl>    <dbl>    <dbl>
1 product   4.20     5.86   0.000339
2 control   1.95     2.55   0.0343 

通过将 df 旋转为长格式,我得到了接近我预期的结果,但只能通过调用我想要比较的级别来工作。也只给出了一个比较,所以我应该调用函数两次。由于我的数据帧的结构始终相同,我可以将以下代码放入 my_ttest_func() 但需要以通用方式引用时间级别。

df %>% pivot_longer(!treatment, names_to = "time", values_to = "values") %>%
  group_by(treatment) %>%
  summarise(across(.cols = values, ~ list(broom::tidy(t.test(.[time == "t2"], 
                                                             .[time == "t0"], 
                                                             alternative = "greater", 
                                                             paired=TRUE)) %>%
             select(statistic, estimate, p.value)))) %>% 
  unnest(values)


  treatment statistic estimate  p.value
  <chr>         <dbl>    <dbl>    <dbl>
1 control        9.90       14 0.000292
2 product        2.83        4 0.0237 

提前致谢

您可以使用嵌套的 map 函数:

library(purrr)
library(dplyr)

df %>% 
  split(~treatment) %>% 
  map_dfr(
    ~.x %>% 
      summarise(
        across(
          3:4, 
          ~t.test(.x, 
                  !!sym(colnames(df)[2]), 
                  alternative = "greater", 
                  paired=TRUE) %>% 
            broom::tidy() %>% 
            select(statistic, estimate, p.value) 
          )
        ) %>% 
        map_dfr(bind_rows, .id = "name"),
    .id = "treatment") %>% 
  arrange(name, treatment)

这个returns

# A tibble: 4 x 5
  treatment name  statistic estimate  p.value
  <chr>     <chr>     <dbl>    <dbl>    <dbl>
1 control   t1         9.90        7 0.000292
2 product   t1         2.83        2 0.0237  
3 control   t2         9.90       14 0.000292
4 product   t2         2.83        4 0.0237  

这不完全是您想要的输出,但您可以继续努力。

由于您的 t0 列始终排在第二位,我们可以在 summarise(across(...)) 结构中使用列名作为 t.test 的输入。

新列 name 包含用于测试的变量 t0