重复测量bootstrap统计数据,按多个因素分组

时间:2017-07-05 13:39:27

标签: r dataframe statistics

我有一个看起来像这样的数据框,但显然还有更多行等等:

df <- data.frame(id=c(1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2),
                 cond=c('A', 'A', 'B', 'B', 'A', 'A', 'B', 'B', 'A', 'A', 'B', 'B', 'A', 'A', 'B', 'B'),
                 comm=c('X', 'Y', 'X', 'Y', 'X', 'Y', 'X', 'Y','X', 'Y', 'X', 'Y', 'X', 'Y', 'X', 'Y'),
                 measure=c(0.8, 1.1, 0.7, 1.2, 0.9, 2.3, 0.6, 1.1, 0.7, 1.3, 0.6, 1.5, 1.0, 2.1, 0.7, 1.2))

因此我们有2个因子(每个因子有2个等级,因此有4个组合)和一个连续测量。我们还有一个重复的度量设计,因为我们在每个单元格中有多个measure对应于相同的id

我试图首先解决groupby问题,然后是引导问题,然后将两者结合起来,但我几乎被卡住了......

统计数据,按2个因素分组

我可以通过以下方式获取4个单元格中的每一个的多个摘要统计数据:

summary_stats <- aggregate(df$measure, 
                           by = list(df$cond, df$comm),
                           function(x) c(mean = mean(x), median = median(x), sd = sd(x)))
print(summary_stats)

导致

  Group.1 Group.2     x.mean   x.median       x.sd
1       A       X 0.85000000 0.85000000 0.12909944
2       B       X 0.65000000 0.65000000 0.05773503
3       A       Y 1.70000000 1.70000000 0.58878406
4       B       Y 1.25000000 1.20000000 0.17320508

这很好,因为我们为4个单元格中的每一个获取了多个统计数据。

但我真正喜欢的是每个统计数据的95%bootstrap CI,对于4个单元格中的每一个。我不介意我必须为统计数据运行一次最终解决方案(例如,平均值,中位数等),但是一次性完成所有操作的奖励积分。

重复测量的Bootstrap

不能完成这项工作,但我想要的是95%的bootstrap CI,以适合这种重复测量设计的方式完成。除非我弄错了,否则我想根据id not 基于数据帧的行)选择bootstrap样本,然后计算摘要度量(例如{ {1}})对于4个单元格中的每一个。

mean

Q1:我在library(boot) myfunc <- function(data, indices) { # select bootstrap sample to index into `id` d <- data[data$id==indicies,] return(c(mean=mean(d), median=median(d), sd = sd(d))) } bresults <- boot(data = CO2$uptake, statistic = myfunc, R = 1000) 选择引导样本时遇到错误,即行id

结合bootstrap和d <- data[ data$id==indicies, ] 2个因素

Q2:我没有直觉知道如何将两种方法凝聚在一起以达到最终的预期效果。我唯一的想法是将groupby调用放入aggregate,重复计算每个bootstrap复制下的单元格统计数据,但是我已经在R的舒适区域之外了。

2 个答案:

答案 0 :(得分:2)

关于你的两个问题,你有两个问题:

  1. 如何以基于id重新取样的方式引导(重新取样)您的数据,而不是行
  2. 如何为2x2设计中的四个组执行单独的bootstraps
  3. 一种简单的方法是使用以下软件包(tidyverse的所有部分):

    • dplyr用于操作您的数据(特别是汇总每个id的数据)以及提供表达式结果的整齐%>%正向管道运算符下一个表达式的第一个参数,以便您可以链接命令
    • broom用于为数据框中的每个组执行操作
    • boot(您已经使用过)用于引导

    加载包裹:

    library(dplyr)
    library(broom)
    library(boot)
    

    首先,为了确保我们重新采样时我们是否包含主题,我会将每个主题的各种值保存为列表:

    df <- df %>%
        group_by(id, cond, comm) %>%
        summarise(measure=list(measure)) %>%
        ungroup()
    

    现在数据帧的行数较少(每个ID 4个),变量measure不再是数字(相反,它是一个列表)。这意味着我们可以只使用boot提供的索引(解决问题1),而且当我们真正想用它进行计算时我们必须“unlist”它,所以你的函数现在变成:

    myfunc <- function(data, indices) {
        data <- data[indices,]
        return(c(mean=mean(unlist(data$measure)),
                 median=median(unlist(data$measure)),
                 sd = sd(unlist(data$measure))))
    }
    

    现在我们可以简单地使用boot对每一行进行重新采样,我们可以考虑如何按组整齐地进行操作。这是broom软件包的来源:您可以要求do对数据框中的每个组进行操作,并将其存储在tidy数据框中,每个数据框各占一行您的组,以及您的函数生成的值的列。因此,我们只需再次对数据框进行分组,然后使用do(tidy(...))而不是变量名称调用.。这有希望为你解决问题2!

    bootresults <- df %>%
        group_by(cond, comm) %>%
        do(tidy(boot(data = ., statistic = myfunc, R = 1000)))
    

    这会产生:

    # Groups:   cond, comm [4]
         cond   comm   term  statistic         bias    std.error
       <fctr> <fctr>  <chr>      <dbl>        <dbl>        <dbl>
     1      A      X   mean 0.85000000  0.000000000 5.280581e-17
     2      A      X median 0.85000000  0.000000000 5.652979e-17
     3      A      X     sd 0.12909944 -0.004704999 4.042676e-02
     4      A      Y   mean 1.70000000  0.000000000 1.067735e-16
     5      A      Y median 1.70000000  0.000000000 1.072347e-16
     6      A      Y     sd 0.58878406 -0.005074338 7.888294e-02
     7      B      X   mean 0.65000000  0.000000000 0.000000e+00
     8      B      X median 0.65000000  0.000000000 0.000000e+00
     9      B      X     sd 0.05773503  0.000000000 0.000000e+00
    10      B      Y   mean 1.25000000  0.001000000 7.283065e-02
    11      B      Y median 1.20000000  0.027500000 7.729634e-02
    12      B      Y     sd 0.17320508 -0.030022214 5.067446e-02
    

    希望这是你想看到的!

    如果您想再使用此数据框中的值,可以使用其他dplyr函数来选择此表中的哪些行。例如,要查看条件A / X的度量标准偏差的自举标准误差,您可以执行以下操作:

    bootresults %>% filter(cond=='A', comm=='X', term=='sd') %>% pull(std.error)
    

    我希望有所帮助!

答案 1 :(得分:2)

对于带有群集变量的引导程序,这里是一个没有附加包的解决方案。我虽然没有使用boot包。

第1部分:引导程序

此函数从一组聚类观察中抽取随机样本。

.clusterSample <- function(x, id){

  boot.id <- sample(unique(id), replace=T)
  out <- lapply(boot.id, function(i) x[id%in%i,])

  return( do.call("rbind",out) )

}

第2部分:Boostrap估算和CI

下一个函数绘制多个样本,并对每个样本应用相同的aggregate语句。然后通过meanquantile获取引导程序估计值和CI。

clusterBoot <- function(data, formula, cluster, R=1000, alpha=.05, FUN){

  # cluster variable
  cls <- model.matrix(cluster,data)[,2]

  template <- aggregate(formula, .clusterSample(data,cls), FUN)
  var <- which( names(template)==all.vars(formula)[1] )
  grp <- template[,-var,drop=F]
  val <- template[,var]

  x <- vapply( 1:R, FUN=function(r) aggregate(formula, .clusterSample(data,cls), FUN)[,var],
               FUN.VALUE=val )

  if(is.vector(x)) dim(x) <- c(1,1,length(x))
  if(is.matrix(x)) dim(x) <- c(nrow(x),1,ncol(x))

  # bootstrap estimates
  est <- apply( x, 1:2, mean )
  lo <- apply( x, 1:2, function(i) quantile(i,alpha/2) )
  up <- apply( x, 1:2, function(i) quantile(i,1-alpha/2) )
  colnames(lo) <- paste0(colnames(lo), ".lo")
  colnames(up) <- paste0(colnames(up), ".up")

  return( cbind(grp,est,lo,up) )

}

请注意vapply的使用。我使用它是因为我更喜欢在列表上使用数组。另请注意,我使用formula接口进行聚合,我也更喜欢。

第3部分:示例

它可以与任何类型的统计数据一起使用,基本上即使没有分组变量也是如此。一些例子包括:

myStats <- function(x) c(mean = mean(x), median = median(x), sd = sd(x))

clusterBoot(data=df, formula=measure~cond+comm, cluster=~id, R=10, FUN=myStats)
#   cond comm mean median         sd mean.lo median.lo      sd.lo mean.up median.up      sd.up
# 1    A    X 0.85  0.850 0.11651125    0.85      0.85 0.05773503    0.85      0.85 0.17320508
# 2    B    X 0.65  0.650 0.05773503    0.65      0.65 0.05773503    0.65      0.65 0.05773503
# 3    A    Y 1.70  1.700 0.59461417    1.70      1.70 0.46188022    1.70      1.70 0.69282032
# 4    B    Y 1.24  1.215 0.13856406    1.15      1.15 0.05773503    1.35      1.35 0.17320508

clusterBoot(data=df, formula=measure~cond+comm, cluster=~id, R=10, FUN=mean)
#   cond comm  est  .lo  .up
# 1    A    X 0.85 0.85 0.85
# 2    B    X 0.65 0.65 0.65
# 3    A    Y 1.70 1.70 1.70
# 4    B    Y 1.25 1.15 1.35

clusterBoot(data=df, formula=measure~1, cluster=~id, R=10, FUN=mean)
#      est    .lo    .up
# 1 1.1125 1.0875 1.1375