## Code author: J. Arbour phylANOVA.intra<-function (tree, X,ycol,f1col,f2col, nsim = 1000,method="anova") { ## This function is modified from the "phytools" package function phylANOVA (Revell, 2012) ## This function carries out an ANOVA/ANCOVA, by comparing the results to a set of Brownian Motion simulated values (following Garland et al. 1993) ## This function can include more than one individual per species by sampling around the BM simulated species mean based on the standard deviation of the trait within each species # tree must be a phy object #X must be a data.frame #col specifies location of variables in dataframe. ycol is the location of the dependent, f1col and f2col are the two factors or the factor (1) and the covariate (2) # method must equal "anova" or "ancova" # nsim is the number of BM simulations # returns a list object with... # 1) $ANOVA: the observed ANOVA/ANCOVA results # 2) $sim.test.pvalue, the phylogenetic significance test associated with the two factors and interaction, or (in the case of ANCOVA) factor, covariate and interaction (null hypothesis: ANOVA/ANCOVA results could have occured under BM evolution) require(HH) mean.perf<-as.vector(by(X[,ycol],X[,1],mean)) sd.perf<-as.vector(by(X[,ycol],X[,1],sd)) names(mean.perf)<-levels(X[,1]) names(sd.perf)<-levels(X[,1]) ace1<-ace(mean.perf,tree)$ace[1] sig2 <- mean(pic(mean.perf, tree)^2) sims.means <- fastBM(tree,a=ace1, sig2 = sig2, nsim = (nsim - 1),bounds=c(0,Inf)) sim.all.data<-matrix(nrow=nrow(X),ncol=(nsim-1)) sd.perf<-sd.perf[unique(X[,1])] if (method=="anova"){ anova.obs <- summary(aov(X[,ycol] ~ X[,f1col]*X[,f2col],X)) for (j in 1:(nsim-1)){ sim.means<-sims.means[,j] sim.means<-sim.means[as.character(names(sd.perf))] for (i in 1:length(levels(X[,1]))){ n<-length(X[,1])/length(levels(X[,1])) new.perf<-rnorm(n,sim.means[i],sd.perf[i]) starts<-n*i-(n-1) stops<-n*i sim.all.data[starts:stops,j]<-new.perf } } F1.null <- vector() F1.null[1] <- anova.obs[[1]]$F[1] F2.null <- vector() F2.null[1] <- anova.obs[[1]]$F[2] FIn.null <- vector() FIn.null[1] <- anova.obs[[1]]$F[3] for (i in 2:nsim) { new.X<-sim.all.data[,(i-1)] anova.new <- summary(aov(new.X ~ X[,f1col]*X[,f2col],X)) F1.null[i] <- anova.new[[1]]$F[1] F2.null[i] <- anova.new[[1]]$F[2] FIn.null[i] <- anova.new[[1]]$F[3] } P.F1 <- sum(F1.null >= F1.null[1])/nsim P.F2 <- sum(F2.null >= F2.null[1])/nsim P.FIn <- sum(FIn.null >= FIn.null[1])/nsim Fs<-c(F1.null[1],F2.null[1],FIn.null[1]) Ps<-c(P.F1,P.F2,P.FIn);names(Ps)<-c("Factor 1", "Factor 2","Interaction") } else{ obs.data<-cbind(X[,ycol],X[,f1col],X[,f2col]) obs.data<-as.data.frame(obs.data) obs.data[,2]<-as.factor(obs.data[,2]) colnames(obs.data)<-c("y","indep","cov") anova.obs <- summary(ancova(y~indep*cov,obs.data)) for (j in 1:(nsim-1)){ sim.means<-sims.means[,j] sim.means<-sim.means[as.character(names(sd.perf))] for (i in 1:length(levels(X[,1]))){ n<-length(X[,1])/length(levels(X[,1])) new.perf<-rnorm(n,sim.means[i],sd.perf[i]) starts<-n*i-(n-1) stops<-n*i sim.all.data[starts:stops,j]<-new.perf } } F1.null <- vector() F1.null[1] <- anova.obs[[1]]$F[1] Fcov.null <- vector() Fcov.null[1] <- anova.obs[[1]]$F[2] FIn.null <- vector() FIn.null[1] <- anova.obs[[1]]$F[3] for (i in 2:nsim) { new.X<-sim.all.data[,(i-1)] new.data<-cbind(new.X,X[,f1col],X[,f2col]) colnames(new.data)<-c("y","indep","cov") new.data<-as.data.frame(new.data) new.data[,2]<-as.factor(new.data[,2]) anova.new <- summary(ancova(y~indep*cov,new.data)) F1.null[i] <- anova.new[[1]]$F[1] Fcov.null[i] <- anova.new[[1]]$F[2] FIn.null[i] <- anova.new[[1]]$F[2] } P.F1 <- sum(F1.null >= F1.null[1])/nsim P.Fcov <- sum(Fcov.null >= Fcov.null[1])/nsim P.FIn<- sum(FIn.null >= FIn.null[1])/nsim Fs<-c(F1.null[1],Fcov.null[1],FIn.null[1]) Ps<-c(P.F1,P.Fcov,P.FIn);names(Ps)<-c("Factor", "Covariate","Interaction") } return(list(ANOVA=anova.obs, sim.test.pvalue=Ps)) }