R apply() 自定义函数到数据框中的每一行

R apply() custom function to every row in data frame

我正在尝试在整个数据框中逐行应用自定义函数。该函数是使用数据框中报告的汇总统计信息的 t 检验,我想在现有数据框中附加函数的四个输出列(均值差、标准误差、t、p 值)。该函数运行良好,但我不确定where/how 将函数的变量调用到数据框中的列。

这是数据框的示例:

MPAmeans <- data.frame(
  group = c("ccfrp","kelp","beach","intertidal"),
   MPA_mean = c(935,974,50.8,935),
   reference_mean = c(388,388,37.6,266),
   sd_MPA = c(208, 488, 85.9, 60),
   sd_reference = c(170, 170, 62, 151),
   n_MPA = c(3,3,3,3),
   n_reference = c(3,3,3,3))

以及我想应用到每一行的函数:

t.test2 <- function(m1,m2,s1,s2,n1,n2,m0=0,equal.variance=FALSE)
{
  if( equal.variance==FALSE ) 
  {
    se <- sqrt( (s1^2/n1) + (s2^2/n2) )
    # welch-satterthwaite df
    df <- ( (s1^2/n1 + s2^2/n2)^2 )/( (s1^2/n1)^2/(n1-1) + (s2^2/n2)^2/(n2-1) )
  } else
  {
    # pooled standard deviation, scaled by the sample sizes
    se <- sqrt( (1/n1 + 1/n2) * ((n1-1)*s1^2 + (n2-1)*s2^2)/(n1+n2-2) ) 
    df <- n1+n2-2
  }      
  t <- (m1-m2-m0)/se 
  dat <- c(m1-m2, se, t, 2*pt(-abs(t),df))  #one tailed m2 > m1. Replace with "2*pt(-abs(t),df))" for two tailed. 
  names(dat) <- c("Difference of means", "Std Error", "t", "p-value")
  return(dat) 
} 

我正在使用 apply(),并在下面列出了对数据框的函数引用...

apply(MPAmeans,
      1,
      t.test2)


m1=reference_mean,
m2=MPA_mean,
s1=sd_reference,
s2=sd_MPA,
n1=n_reference,
n2=n_MPA

如何 reference/call apply() 中的函数变量,然后将四个新列附加到数据框?

我们可以在循环后使用 lambda 函数 (function(x)) 一个一个地指定参数,或者创建一个命名的 list 并使用 do.call

apply(MPAmeans[c(3, 2, 5, 4, 7, 6)], 1, function(x) 
   do.call(t.test2, setNames(as.list(x), as.list(args(t.test2))[1:6])))

-输出

                          [,1]         [,2]        [,3]          [,4]
Difference of means -547.00000000 -586.0000000 -13.2000000 -6.690000e+02
Std Error            155.09566940  298.3532582  61.1631970  9.381009e+01
t                     -3.52685541   -1.9641146  -0.2158161 -7.131429e+00
p-value                0.02590082    0.1632975   0.8406800  8.798398e-03

另一种方法是修改现有函数,使其矢量化。

    t.test2 <- function(m1,m2,s1,s2,n1,n2,m0=0,equal.variance=FALSE)
{
    if(!equal.variance) 
    {
        se <- sqrt( (s1^2/n1) + (s2^2/n2) )
        # welch-satterthwaite df
        df <- ( (s1^2/n1 + s2^2/n2)^2 )/( (s1^2/n1)^2/(n1-1) + (s2^2/n2)^2/(n2-1) )
    } else
    {
        # pooled standard deviation, scaled by the sample sizes
        se <- sqrt( (1/n1 + 1/n2) * ((n1-1)*s1^2 + (n2-1)*s2^2)/(n1+n2-2) ) 
        df <- n1+n2-2
    }      
    t <- (m1-m2-m0)/se 
    dat <- vapply(seq_len(length(m1)), 
                  function(x){c(m1[x]-m2[x], se[x], t[x], 2*pt(-abs(t[x]),df[x]))},
                  numeric(4))  #one tailed m2 > m1. Replace with "2*pt(-abs(t),df))" for two tailed. 
    dat <- t(dat)
    dat <- as.data.frame(dat)
    names(dat) <- c("Difference of means", "Std Error", "t", "p-value")
    return(dat) 
} 

这种方法允许您为各种输入传递向量,它会为您的输入提供一个长度相等的数据帧。它使用 vapply 函数为每个提供的值 return 一个长度为 4 的向量。

在这种方式下,你可以直接去

t.test2(MPAmeans$reference_mean, MPAmeans$MPA_mean, MPAmeans$sd_reference, MPAmeans$sd_MPA, MPAmeans$n_reference, MPAmeans$n_MPA)

(或您最终调用变量的任何内容)