R and Analysis of Variance
A special case of the linear model is the situation where the predictor variables are categorical. In psychological research this usually reflects experimental design where the independent variables are multiple levels of some experimental manipulation (e.g., drug administration, recall instructions, etc.)
The first 5 examples are adapted from the guide to S+ developed by TAs for Roger Ratcliff. For more detail on data entry consult that guide. The last three examples discuss how to reorganize the data from a standard data frame into one appropriate for within subject analyses. For this discussion, I assume that appropriate data files have been created in a text editor and saved in a subjects x variables table.
One Way Analysis of Variance
Example 1: Three levels of drug were administered to 18 subjects. Do descriptive statistics on the groups, and then do a one way analysis of variance. The ANOVA command is aov:
aov.ex1= aov(Alertness~Dosage,data=ex1)
It is important to note the order of the arguments. The first argument is always the dependent variable (Alertness ). It is followed by the tilde symbol (~) and the independent variable(s). The final argument for aov is the name of the data structure that is being analyzed. aov.ex1 is the name of the structure you want the analysis to store. This general format will hold true for all ANOVAs you will conduct.
The results of the ANOVA can be seen with the summary command:
#tell where the data come from datafilename="http://personality-project.org/R/datasets/R.appendix1.data" data.ex1=read.table(datafilename,header=T) #read the data into a table aov.ex1 = aov(Alertness~Dosage,data=data.ex1) #do the analysis of variance summary(aov.ex1) #show the summary table print(model.tables(aov.ex1,"means"),digits=3) #report the means and the number of subjects/cell boxplot(Alertness~Dosage,data=data.ex1) #graphical summary
produces this output
> datafilename="http://personality-project.org/r/datasets/R.appendix1.data" > data.ex1=read.table(datafilename,header=T) #read the data into a table > > aov.ex1 = aov(Alertness~Dosage,data=data.ex1) #do the analysis of variance > summary(aov.ex1) #show the summary table Df Sum Sq Mean Sq F value Pr(>F) Dosage 2 426.25 213.12 8.7887 0.002977 ** Residuals 15 363.75 24.25 --- Signif. codes: 0 `***' 0.001 `**' 0.01 `*' 0.05 `.' 0.1 ` ' 1 > print(model.tables(aov.ex1,"means"),digits=3) #report the means and the number of subjects/cell Tables of means Grand mean 27.66667 Dosage a b c 32.5 28.2 19.2 rep 6.0 8.0 4.0
Two way - between subject analysis of variance
Data are from an experiment in which alertness level of male and female subjects was measured after they had been given one of two possible dosages of a drug. Thus, this is a 2X2 design with the factors being Gender and Dosage. Read the data file containing this data. Notice that there are two independent variables in this example, separated by an asterisk *. The asterisk indicates to R that the interaction between the two factors is interesting and should be analyzed. If interactions are not important, replace the asterisk with a plus sign (+).
Run the analysis:
datafilename="http://personality-project.org/r/datasets/R.appendix2.data" data.ex2=read.table(datafilename,header=T) #read the data into a table data.ex2 #show the data aov.ex2 = aov(Alertness~Gender*Dosage,data=data.ex2) #do the analysis of variance summary(aov.ex2) #show the summary table print(model.tables(aov.ex2,"means"),digits=3) #report the means and the number of subjects/cell boxplot(Alertness~Dosage*Gender,data=data.ex2) #graphical summary of means of the 4 cells
The output should look like the following:
> datafilename="http://personality-project.org/r/datasets/R.appendix2.data" > data.example2=read.table(datafilename,header=T) #read the data into a table > data.example2 #show the data Observation Gender Dosage Alertness 1 1 m a 8 2 2 m a 12 3 3 m a 13 4 4 m a 12 5 5 m b 6 6 6 m b 7 7 7 m b 23 8 8 m b 14 9 9 f a 15 10 10 f a 12 11 11 f a 22 12 12 f a 14 13 13 f b 15 14 14 f b 12 15 15 f b 18 16 16 f b 22 > aov.ex2 = aov(Alertness~Gender*Dosage,data=data.example2) #do the analysis of variance > summary(aov.ex2) #show the summary table Df Sum Sq Mean Sq F value Pr(>F) Gender 1 76.562 76.562 2.9518 0.1115 Dosage 1 5.062 5.062 0.1952 0.6665 Gender:Dosage 1 0.063 0.063 0.0024 0.9617 Residuals 12 311.250 25.938 > print(model.tables(aov.ex2,"means"),digits=3) #report the means and the number of subjects/cell Tables of means Grand mean 14.0625 Gender f m 16.2 11.9 rep 8.0 8.0 Dosage a b 13.5 14.6 rep 8.0 8.0 Gender:Dosage Dosage Gender a b f 15.75 16.75 rep 4.00 4.00 m 11.25 12.50 rep 4.00 4.00
The generalization to n way ANOVA is straightforward.
1 way ANOVA - within subjects
Example 3. One-Way Within-Subjects ANOVA
Five subjects are asked to memorize a list of words. The words on this list are of three types: positive words, negative words and neutral words. Their recall data by word type is displayed in Appendix III. Note that there is a single factor (Valence ) with three levels (negative, neutral and positive). In addition, there is also a random factor Subject . Create a data file ex3 that contains this data. Again it is important that each observation appears on an individual line! Note that this is not the standard way of thinking about data. Example 6 will show how to transform data from the standard data table into this form.
#Run the analysis: datafilename="http://personality-project.org/r/datasets/R.appendix3.data" data.ex3=read.table(datafilename,header=T) #read the data into a table data.ex3 #show the data aov.ex3 = aov(Recall~Valence+Error(Subject/Valence),data.ex3) summary(aov.ex3) print(model.tables(aov.ex3,"means"),digits=3) #report the means and the number of subjects/cell boxplot(Recall~Valence,data=data.ex3) #graphical output
Because Valence is crossed with the random factor Subject (i.e., every subject sees all three types of words), you must specify the error term for Valence , which in this case is Subject by Valence . Do this by adding the termError(Subject/Valence) to the factor Valence , as shown above. The output will look like:
> datafilename="http://personality-project.org/r/datasets/R.appendix3.data" > data.ex3=read.table(datafilename,header=T) #read the data into a table > data.ex3 #show the data Observation Subject Valence Recall 1 1 Jim Neg 32 2 2 Jim Neu 15 3 3 Jim Pos 45 4 4 Victor Neg 30 5 5 Victor Neu 13 6 6 Victor Pos 40 7 7 Faye Neg 26 8 8 Faye Neu 12 9 9 Faye Pos 42 10 10 Ron Neg 22 11 11 Ron Neu 10 12 12 Ron Pos 38 13 13 Jason Neg 29 14 14 Jason Neu 8 15 15 Jason Pos 35 > aov.ex3 = aov(Recall~Valence+Error(Subject/Valence),data.ex3) > summary(aov.ex3) Error: Subject Df Sum Sq Mean Sq F value Pr(>F) Residuals 4 105.067 26.267 Error: Subject:Valence Df Sum Sq Mean Sq F value Pr(>F) Valence 2 2029.73 1014.87 189.11 1.841e-07 *** Residuals 8 42.93 5.37 --- Signif. codes: 0 `***' 0.001 `**' 0.01 `*' 0.05 `.' 0.1 ` ' 1 > print(model.tables(aov.ex3,"means"),digits=3) #report the means and the number of subjects/cell Tables of means Grand mean 26.46667 Valence Valence Neg Neu Pos 27.8 11.6 40.0
The analysis of between-subjects factors will appear first (there are none in this case), followed by the within-subjects factors. Note that the p value for Valence is displayed in exponential notation; this occurs when the p value is extremely low, as it is in this case (approximately .00000018).
Two-way Within Subjects ANOVA
Example 4. Two-Way Within-Subjects ANOVA
In this example, Subject is crossed with both Task and Valence, so you must specify three different error terms: one forTask , one for Valence and one for the interaction between the two. Fortunately, R is smart enough to divide up the within-subjects error term properly as long as you specify it in your command. The commands are:
datafilename="http://personality-project.org/r/datasets/R.appendix4.data" data.ex4=read.table(datafilename,header=T) #read the data into a table data.ex4 #show the data aov.ex4=aov(Recall~(Task*Valence)+Error(Subject/(Task*Valence)),data.ex4 ) summary(aov.ex4) print(model.tables(aov.ex4,"means"),digits=3) #report the means and the number of subjects/cell boxplot(Recall~Task*Valence,data=data.ex4) #graphical summary of means of the 6 cells
results in the following output:
> datafilename="http://personality-project.org/r/datasets/R.appendix4.data" > data.example4=read.table(datafilename,header=T) #read the data into a table > data.example4 #show the data Observation Subject Task Valence Recall 1 1 Jim Free Neg 8 2 2 Jim Free Neu 9 3 3 Jim Free Pos 5 4 4 Jim Cued Neg 7 5 5 Jim Cued Neu 9 6 6 Jim Cued Pos 10 7 7 Victor Free Neg 12 8 8 Victor Free Neu 13 9 9 Victor Free Pos 14 10 10 Victor Cued Neg 16 11 11 Victor Cued Neu 13 12 12 Victor Cued Pos 14 13 13 Faye Free Neg 13 14 14 Faye Free Neu 13 15 15 Faye Free Pos 12 16 16 Faye Cued Neg 15 17 17 Faye Cued Neu 16 18 18 Faye Cued Pos 14 19 19 Ron Free Neg 12 20 20 Ron Free Neu 14 21 21 Ron Free Pos 15 22 22 Ron Cued Neg 17 23 23 Ron Cued Neu 18 24 24 Ron Cued Pos 20 25 25 Jason Free Neg 6 26 26 Jason Free Neu 7 27 27 Jason Free Pos 9 28 28 Jason Cued Neg 4 29 29 Jason Cued Neu 9 30 30 Jason Cued Pos 10 > aov.ex4=aov(Recall~(Task*Valence)+Error(Subject/(Task*Valence)),data.example4 ) > > summary(aov.ex4) Error: Subject Df Sum Sq Mean Sq F value Pr(>F) Residuals 4 349.13 87.28 Error: Subject:Task Df Sum Sq Mean Sq F value Pr(>F) Task 1 30.0000 30.0000 7.3469 0.05351 . Residuals 4 16.3333 4.0833 --- Signif. codes: 0 `***' 0.001 `**' 0.01 `*' 0.05 `.' 0.1 ` ' 1 Error: Subject:Valence Df Sum Sq Mean Sq F value Pr(>F) Valence 2 9.8000 4.9000 1.4591 0.2883 Residuals 8 26.8667 3.3583 Error: Subject:Task:Valence Df Sum Sq Mean Sq F value Pr(>F) Task:Valence 2 1.4000 0.7000 0.2907 0.7553 Residuals 8 19.2667 2.4083 > print(model.tables(aov.ex4,"means"),digits=3) #report the means and the number of subjects/cell Tables of means Grand mean 11.8 Task Cued Free 12.8 10.8 rep 15.0 15.0 Valence Neg Neu Pos 11 12.1 12.3 rep 10 10.0 10.0 Task:Valence Valence Task Neg Neu Pos Cued 11.8 13.0 13.6 rep 5.0 5.0 5.0 Free 10.2 11.2 11.0 rep 5.0 5.0 5.0
Mixed (between and Within) designs
Now it's time to get serious. Appendix V contains the data of an experiment with 18 subjects, 9 males and 9 females. Each subject is given one of three possible dosages of a drug. All subjects are then tested on recall of three types of words (positive, negative and neutral) using two types of memory tasks (cued and free recall). There are thus 2 between-subjects variables: Gender (2 levels) and Dosage (3 levels); and 2 within-subjects variables: Task (2 levels) and Valence (3 levels). Get the data from the file and run the following analysis:
aov.ex5 _ aov(Recall~(Task*Valence*Gender*Dosage)+Error(Subject/(Task*Valence))+(Gender*Dosage),ex5)
Notice that you must segregate between- and within-subjects variables in your command. In the above example, I have put the within-subjects factors first with the within-subjects error term, followed by the between-subjects factors.
datafilename="http://personality-project.org/r/datasets/R.appendix5.data" data.ex5=read.table(datafilename,header=T) #read the data into a table data.ex5 #show the data aov.ex5 = aov(Recall~(Task*Valence*Gender*Dosage)+Error(Subject/(Task*Valence))+(Gender*Dosage),data.ex5 ) summary(aov.ex5) print(model.tables(aov.ex5,"means"),digits=3) #report the means and the number of subjects/cell boxplot(Recall~Task*Valence*Gender*Dosage,data=data.ex5) #graphical summary of means of the 36 cells boxplot(Recall~Task*Valence*Dosage,data=data.ex5) #graphical summary of means of 18 cells
Should result in the following (extensive) output:
> datafilename="http://personality-project.org/r/datasets/R.appendix5.data" > data.example5=read.table(datafilename,header=T) #read the data into a table > data.example5 #show the data Obs Subject Gender Dosage Task Valence Recall 1 1 A M A F Neg 8 2 2 A M A F Neu 9 3 3 A M A F Pos 5 4 4 A M A C Neg 7 5 5 A M A C Neu 9 6 6 A M A C Pos 10 7 7 B M A F Neg 12 8 8 B M A F Neu 13 9 9 B M A F Pos 14 10 10 B M A C Neg 16 ... SNIP .... 100 100 Q F C C Neg 17 101 101 Q F C C Neu 19 102 102 Q F C C Pos 19 103 103 R F C F Neg 19 104 104 R F C F Neu 17 105 105 R F C F Pos 19 106 106 R F C C Neg 22 107 107 R F C C Neu 21 108 108 R F C C Pos 20 > aov.ex5=aov.ex5 = aov(Recall~(Task*Valence*Gender*Dosage)+Error(Subject/(Task*Valence))+(Gender*Dosage),data.example5 ) > > summary(aov.ex5) Error: Subject Df Sum Sq Mean Sq F value Pr(>F) Gender 1 542.26 542.26 5.6853 0.03449 * Dosage 2 694.91 347.45 3.6429 0.05803 . Gender:Dosage 2 70.80 35.40 0.3711 0.69760 Residuals 12 1144.56 95.38 --- Signif. codes: 0 `***' 0.001 `**' 0.01 `*' 0.05 `.' 0.1 ` ' 1 Error: Subject:Task Df Sum Sq Mean Sq F value Pr(>F) Task 1 96.333 96.333 39.8621 3.868e-05 *** Task:Gender 1 1.333 1.333 0.5517 0.4719 Task:Dosage 2 8.167 4.083 1.6897 0.2257 Task:Gender:Dosage 2 3.167 1.583 0.6552 0.5370 Residuals 12 29.000 2.417 --- Signif. codes: 0 `***' 0.001 `**' 0.01 `*' 0.05 `.' 0.1 ` ' 1 Error: Subject:Valence Df Sum Sq Mean Sq F value Pr(>F) Valence 2 14.685 7.343 2.9981 0.06882 . Valence:Gender 2 3.907 1.954 0.7977 0.46193 Valence:Dosage 4 20.259 5.065 2.0681 0.11663 Valence:Gender:Dosage 4 1.037 0.259 0.1059 0.97935 Residuals 24 58.778 2.449 --- Signif. codes: 0 `***' 0.001 `**' 0.01 `*' 0.05 `.' 0.1 ` ' 1 Error: Subject:Task:Valence Df Sum Sq Mean Sq F value Pr(>F) Task:Valence 2 5.389 2.694 1.3197 0.2859 Task:Valence:Gender 2 2.167 1.083 0.5306 0.5950 Task:Valence:Dosage 4 2.778 0.694 0.3401 0.8482 Task:Valence:Gender:Dosage 4 2.667 0.667 0.3265 0.8574 Residuals 24 49.000 2.042 > print(model.tables(aov.ex5,"means"),digits=3) #report the means and the number of subjects/cell Tables of means Grand mean 15.62963 Task C F 16.6 14.7 rep 54.0 54.0 Valence Neg Neu Pos 15.3 15.5 16.1 rep 36.0 36.0 36.0 Gender F M 17.9 13.4 rep 54.0 54.0 Dosage A B C 14.2 13.5 19.2 rep 36.0 36.0 36.0 Task:Valence Valence Task Neg Neu Pos C 16.00 16.72 17.00 rep 18.00 18.00 18.00 F 14.56 14.22 15.28 rep 18.00 18.00 18.00 Task:Gender Gender Task F M C 18.93 14.22 rep 27.00 27.00 F 16.81 12.56 rep 27.00 27.00 Valence:Gender Gender Valence F M Neg 17.67 12.89 rep 18.00 18.00 Neu 17.44 13.50 rep 18.00 18.00 Pos 18.50 13.78 rep 18.00 18.00 ... snip .... , , Gender = M, Dosage = B Valence Task Neg Neu Pos C 10.00 11.67 12.33 rep 3.00 3.00 3.00 F 8.33 8.67 11.00 rep 3.00 3.00 3.00 , , Gender = F, Dosage = C Valence Task Neg Neu Pos C 20.67 21.67 21.33 rep 3.00 3.00 3.00 F 19.67 18.67 20.33 rep 3.00 3.00 3.00 , , Gender = M, Dosage = C Valence Task Neg Neu Pos C 18.00 19.00 19.00 rep 3.00 3.00 3.00 F 17.33 17.33 17.33 rep 3.00 3.00 3.00
Reorganizing the data for within subject analyses
The prior examples have assumed one line per unique subject/variable combination. This is not a typical way to enter data. A more typical way (found e.g., in Systat) is to have one row/subject. We need to "stack" the data to go from the standard input to the form preferred by the analysis of variance. Consider the following analyses of 27 subjects doing a memory study of the effect on recall of two presentation rates and two recall intervals. Each subject has two replications per condition. The first 8 columns are the raw data, the last 4 columns collapse across replications. The data are found in a file on the personality project server.
datafilename="http://personality-project.org/r/datasets/recall1.data" data=read.table(datafilename,header=TRUE) data #show the data
We can use the "stack() function to arrange the data in the correct manner. We then need to create a new data.frame (recall.df) to attach the correct labels to the correct conditions. This seems more complicated than it really is (although it is fact somewhat tricky). It is useful to list the data after the data frame operation to make sure that we did it correctly. (This and the next example are adapted from Baron and Li's page. ) We make use of the rep(), c(), and factor() functions.
rep (operation,number) repeats an operation number timesc(x,y) forms a vector with x and y elements
factor (vector) converts a numeric vector into factors for an ANOVA
sums=data[,9:12] #get the summary numbers stackeds=stack(sums) #convert to a column vector to do anova with repeated measures #stackeds #show the data as they are now reorganized numcases=27 #How many subjects are there? numvariables=4 #How many repeated measures are there? recall.df=data.frame(recall=stackeds, subj=factor(rep(paste("subj", 1:numcases, sep=""), numvariables)), time=factor(rep(rep(c("short", "long"), c(numcases, numcases)), 2)), study=factor(rep(c("d45", "d90"), c(numcases*2, numcases*2)))) recall.df #show the results of stacking and forming the data.frame #now, do the within subjects ANOVA and show the results recall.aov= aov(recall.values ~ time * study + Error(subj/(time * study)), data=recall.df) summary(recall.aov) print(model.tables(recall.aov,"means"),digits=3)
results in the following output:
sums=data[,9:12] #get the summary numbers > stackeds=stack(sums) #convert to a column vector to do anova with repeated measures > #stackeds #show the data as they are now reorganized > > numcases=27 #How many subjects are there? > numvariables=4 #How many repeated measures are there? > > recall.df=data.frame(recall=stackeds, + subj=factor(rep(paste("subj", 1:numcases, sep=""), numvariables)), + time=factor(rep(rep(c("short", "long"), c(numcases, numcases)), 2)), + study=factor(rep(c("d45", "d90"), c(numcases*2, numcases*2)))) > recall.df recall.values recall.ind subj time study 1 13 ss subj1 short d45 2 25 ss subj2 short d45 .snip .. 25 17 ss subj25 short d45 26 19 ss subj26 short d45 27 19 ss subj27 short d45 28 10 sl subj1 long d45 29 13 sl subj2 long d45 30 16 sl subj3 long d45 .snip.. 79 21 ls subj25 short d90 80 22 ls subj26 short d90 81 21 ls subj27 short d90 82 17 ll subj1 long d90 .snip ... 108 20 ll subj27 long d90 > recall.aov= aov(recall.values ~ time * study + Error(subj/(time * study)), data=recall.df) > summary(recall.aov) Error: subj Df Sum Sq Mean Sq F value Pr(>F) Residuals 26 1175.35 45.21 Error: subj:time Df Sum Sq Mean Sq F value Pr(>F) time 1 1.333 1.333 0.2249 0.6393 Residuals 26 154.167 5.929 Error: subj:study Df Sum Sq Mean Sq F value Pr(>F) study 1 166.259 166.259 14.997 0.0006512 *** Residuals 26 288.241 11.086 --- Signif. codes: 0 `***' 0.001 `**' 0.01 `*' 0.05 `.' 0.1 ` ' 1 Error: subj:time:study Df Sum Sq Mean Sq F value Pr(>F) time:study 1 71.704 71.704 6.8592 0.01452 * Residuals 26 271.796 10.454 --- Signif. codes: 0 `***' 0.001 `**' 0.01 `*' 0.05 `.' 0.1 ` ' 1 > print(model.tables(recall.aov,"means"),digits=3) Tables of means Grand mean 18.53704 time long short 18.4 18.6 rep 54.0 54.0 study d45 d90 17.3 19.8 rep 54.0 54.0 time:study study time d45 d90 long 16.37 20.48 rep 27.00 27.00 short 18.22 19.07 rep 27.00 27.00
We can use this same procedure of stacking and forming a data frame on the raw data and consider replications as part of the design. I have written this code in a generic form so that it is (somewhat) easier to use for other data sets. The nex three analyses compare the effects of including the subject replication as part of the design.
raw=data[,1:8] #just trial data #First set some specific paremeters for the analysis -- this allows numcases=27 #How many subjects are there? numvariables=8 #How many repeated measures are there? numreplications=2 #How many replications/subject? numlevels1=2 #specify the number of levels for within subject variable 1 numlevels2=2 #specify the number of levels for within subject variable 2 stackedraw=stack(raw) #convert the data array into a vector #add the various coding variables for the conditions #make sure to check that this coding is correct recall.raw.df=data.frame(recall=stackedraw, subj=factor(rep(paste("subj", 1:numcases, sep=""), numvariables)), replication=factor(rep(rep(c("1","2"), c(numcases, numcases)), numvariables/numreplications)), time=factor(rep(rep(c("short", "long"), c(numcases*numreplications, numcases*numreplications)),numlevels1)), study=rep(c("d45", "d90") ,c(numcases*numlevels1*numreplications,numcases*numlevels1*numreplications))) recall.aov= aov(recall.values ~ time * study + Error(subj/(time * study)), data=recall.raw.df) #do the ANOVA summary(recall.aov) #show the output print(model.tables(recall.aov,"means"),digits=3) #show the cell means for the anova table #compare with the complete analysis recall.aov= aov(recall.values ~ time * study*replication + Error(subj/(time * study * replication)), data=recall.raw.df) #do the ANOVA summary(recall.aov) #show the output print(model.tables(recall.aov,"means"),digits=3) #show the cell means for the anova table > recall.aov= aov(recall.values ~ time * study + Error(subj/(time * study)), data=recall.raw.df) #do the ANOVA > summary(recall.aov) #show the output Error: subj Df Sum Sq Mean Sq F value Pr(>F) Residuals 26 587.68 22.60 Error: subj:time Df Sum Sq Mean Sq F value Pr(>F) time 1 0.667 0.667 0.2249 0.6393 Residuals 26 77.083 2.965 Error: subj:study Df Sum Sq Mean Sq F value Pr(>F) study 1 83.130 83.130 14.997 0.0006512 *** Residuals 26 144.120 5.543 --- Signif. codes: 0 `***' 0.001 `**' 0.01 `*' 0.05 `.' 0.1 ` ' 1 Error: subj:time:study Df Sum Sq Mean Sq F value Pr(>F) time:study 1 35.852 35.852 6.8592 0.01452 * Residuals 26 135.898 5.227 --- Signif. codes: 0 `***' 0.001 `**' 0.01 `*' 0.05 `.' 0.1 ` ' 1 Error: Within Df Sum Sq Mean Sq F value Pr(>F) Residuals 108 586.00 5.43 > print(model.tables(recall.aov,"means"),digits=3) #show the cell means for the anova table Tables of means Grand mean 9.268519 time long short 9.21 9.32 rep 108.00 108.00 study d45 d90 8.65 9.89 rep 108.00 108.00 time:study study time d45 d90 long 8.2 10.2 rep 54.0 54.0 short 9.1 9.5 rep 54.0 54.0 > > #compare with the complete analysis > recall.aov= aov(recall.values ~ time * study*replication + Error(subj/(time * study * replication)), data=recall.raw.df) #do the ANOVA > summary(recall.aov) #show the output Error: subj Df Sum Sq Mean Sq F value Pr(>F) Residuals 26 587.68 22.60 Error: subj:time Df Sum Sq Mean Sq F value Pr(>F) time 1 0.667 0.667 0.2249 0.6393 Residuals 26 77.083 2.965 Error: subj:study Df Sum Sq Mean Sq F value Pr(>F) study 1 83.130 83.130 14.997 0.0006512 *** Residuals 26 144.120 5.543 --- Signif. codes: 0 `***' 0.001 `**' 0.01 `*' 0.05 `.' 0.1 ` ' 1 Error: subj:replication Df Sum Sq Mean Sq F value Pr(>F) replication 1 4.741 4.741 0.7208 0.4036 Residuals 26 171.009 6.577 Error: subj:time:study Df Sum Sq Mean Sq F value Pr(>F) time:study 1 35.852 35.852 6.8592 0.01452 * Residuals 26 135.898 5.227 --- Signif. codes: 0 `***' 0.001 `**' 0.01 `*' 0.05 `.' 0.1 ` ' 1 Error: subj:time:replication Df Sum Sq Mean Sq F value Pr(>F) time:replication 1 88.167 88.167 38.153 1.563e-06 *** Residuals 26 60.083 2.311 --- Signif. codes: 0 `***' 0.001 `**' 0.01 `*' 0.05 `.' 0.1 ` ' 1 Error: subj:study:replication Df Sum Sq Mean Sq F value Pr(>F) study:replication 1 16.667 16.667 3.8662 0.06003 . Residuals 26 112.083 4.311 --- Signif. codes: 0 `***' 0.001 `**' 0.01 `*' 0.05 `.' 0.1 ` ' 1 Error: subj:time:study:replication Df Sum Sq Mean Sq F value Pr(>F) time:study:replication 1 0.463 0.463 0.0906 0.7657 Residuals 26 132.787 5.107 > print(model.tables(recall.aov,"means"),digits=3) #show the cell means for the anova table Tables of means Grand mean 9.268519 time long short 9.21 9.32 rep 108.00 108.00 study d45 d90 8.65 9.89 rep 108.00 108.00 replication 1 2 9.12 9.42 rep 108.00 108.00 time:study study time d45 d90 long 8.2 10.2 rep 54.0 54.0 short 9.1 9.5 rep 54.0 54.0 time:replication replication time 1 2 long 8.4 10.0 rep 54.0 54.0 short 9.8 8.8 rep 54.0 54.0 study:replication replication study 1 2 d45 8.2 9.1 rep 54.0 54.0 d90 10.0 9.8 rep 54.0 54.0 time:study:replication , , replication = 1 study time d45 d90 long 7.07 9.78 rep 27.00 27.00 short 9.37 10.26 rep 27.00 27.00 , , replication = 2 study time d45 d90 long 9.30 10.70 rep 27.00 27.00 short 8.85 8.81 rep 27.00 27.00