我一直在文档和论坛中搜索很长时间,但是我仍然很难理解如何使用apply函数而不是R中的循环来实现更复杂的函数。 (对于像apply(data,1,sum)这样的函数,它确实可以)
例如我有以下功能
AOV_GxT=function(Trial_group,trait,df){
sub_table=df[which(df$Trial.group == Trial_group),]
aov_GxT = anova(aov(sub_table[,trait] ~ Genotype + Treatment + Treatment/Rep.number + Genotype*Treatment, data=sub_table, na.action="na.omit"))
pvalue = aov_GxT$"Pr(>F)"[2]
return(c(Trial_group,trait,pvalue))
}
我想从数据框Trial_groups
traits
和每个df
(在列中)
因此我通常会做以下事情(完美无缺):
aov_table=data.frame(matrix(ncol=4))
colnames(aov_table)=c("Trial_group", "Trait", "pvalue G*T")
for(trait in colnames(dataset)[2:ncol(dataset)]){
for(Trial_group in unique(dataset[,'Trial.group'])){
aov_table<-cbind (aov_table,AOV_GxT(Trial_group,trait,dataset))
}
dataset
是一个包含数据的数据框,以及包含函数中aov因子的更多列。
head(dataset)
Trial.group Trait1 Trait2 Trait3
A 0.4709055 0.6123510 0.7098447
B 0.4973123 0.6322532 0.7336145
C 0.4955180 0.6243369 0.7336492
D 0.4787380 0.6235426 0.7304343
E 0.5137033 0.6418851 0.7364666
F 0.4524246 0.5975655 0.7012825
我想限制循环的使用并了解如何使用apply
系列函数,因此我创建了列表并尝试使用mapply
:
trait_lst = list(colnames(df_vars_clean)[7:ncol(df_vars_clean)])
Tgrp_lst = list(unique(df_vars_clean[,'Trial.group']))
aov_table<-mapply(AOV_GxT(a,b,c),a=Tgrp_lst,b=trait_lst, c=dataset )
然后它给了我函数中子集的错误,我想是因为我尝试从列表中做一个子集:
'builtin'类型的对象不是子集
我知道我的代码可能存在一些错误,但我自己一直在学习R,并且有一些我目前不太了解的概念。
我如何在我的函数上使用apply而不是for for循环?
感谢。
答案 0 :(得分:2)
正如评论中指出的那样,ddply是不错的选择,然而,这个问题很容易通过lapply来解决:
do.call(rbind, lapply(split(dataset, dataset$Trial.Group), function(tgDf) {
do.call(rbind, lapply(c("Trait1", "Trait2", "Trait3"), function(trait) {
## you don't need the trial group, it is already subsetted.
AOV_gtx(trait, tgDf)
}))
}))
使用ddply你会删除外部lapply / split代码:
ddply(dataset, "Trial.Group", function(tgDf) {
## the code in here would be the same, because you are iterating over
## the response cols.
})
具有所有这些函数的密钥,以及通常的R,是不预先分配数据结构来存储结果 - 它是有用的,因此您将构建结果然后返回它们。