我有一个看起来像这样的数据框,但显然还有更多行等等:
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个因素
groupby
调用放入aggregate
,重复计算每个bootstrap复制下的单元格统计数据,但是我已经在R的舒适区域之外了。
答案 0 :(得分:2)
关于你的两个问题,你有两个问题:
id
重新取样的方式引导(重新取样)您的数据,而不是行一种简单的方法是使用以下软件包(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
语句。然后通过mean
和quantile
获取引导程序估计值和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