Join our Community Groups and get customized solutions Join Now! Watch Tutorials Youtube

How to Do ANOVA in R I Step-by-Step Guide

Discover how to conduct an analysis of variance (ANOVA) test in R to compare multiple groups. A step-by-step guide covering one-way and two-way ANOVA.

Have you ever wondered how to compare the means of more than two groups in a statistical analysis? 

If you have, you might have heard of ANOVA in R or analysis of variance. ANOVA is a powerful and widely used technique that allows you to test the hypothesis that the means of several populations are equal. 

  • But how do you perform ANOVA in R, the popular data-analysis programming language? 
  • And what are the steps and assumptions involved in this method? 

Using a comprehensive step-by-step guide, this article will show you how to do ANOVA in R. 

Table of Contents

Key points

  • ANOVA is used to compare the means of an outcome variable across different levels of one or more factors, such as one-way ANOVA and two-way ANOVA.
  • ANOVA can be performed in R using the aov function, 
  • ANOVA can be used to test hypotheses, which involve formulating the null and alternative hypotheses, performing the F-test, and deciding based on the p-value and the significance level.
  • ANOVA can also be used to analyze the results, which involve comparing different models or terms using the ANOVA function, performing posthoc tests using the Tukey HSD function, and calculating the effect size using the eta squared function.
  • ANOVA can encounter common issues and challenges, such as troubleshooting errors, meeting assumptions, interpreting results, handling categorical data, and optimizing test setup and execution.

What is ANOVA?

It is a statistical method used to compare the means of two or more groups and test hypotheses about their differences.  For example, compare student's average scores from different schools, the average heights of plants grown under different conditions, or the average sales of products from different regions. ANOVA can help you answer these questions and more. 

ANOVA is based on the idea that the variation in the data can be partitioned into two components: 

  • the variation between the groups
  • the variation within the groups.

ANOVA can help you determine whether the variation between the groups is significantly larger than the variation within the groups, which implies that the groups have different means. ANOVA in R can be performed using the aov function:

aov(formula, data)
  • The formula argument specifies the outcome and factor variables, separated by a tilde (~).
  • The data argument specifies the name of the data frame that contains the variables. 

Types of ANOVA

Type of ANOVA Description Key Differences R Code for Implementation
One-Way ANOVA Used to compare means of three or more groups when there is only one independent variable. Focuses on a single factor, providing an overall test for differences in group means. aov(dependent_variable ~ factor, data=data_frame)
Two-Way ANOVA It incorporates two independent variables, examining their main effects and interactions. Allows the assessment of how two factors simultaneously influence the dependent variable and their interaction effect. aov(dependent_variable ~ factor1 * factor2, data=data_frame)
Multi-level ANOVA Deals with nested or hierarchical data structures, accommodating varied levels of grouping. Useful when observations are organized hierarchically, considering the influence of multiple grouping factors on the dependent variable. aov(dependent_variable ~ factor1 + Error(nesting_factor/factor2), data=data_frame)
Mixed-Effects ANOVA Combines fixed effects (similar to one-way or two-way ANOVA) with random effects. Suitable for designs with both fixed and random factors, capturing variability due to controlled and uncontrolled factors. library(lme4)
lmer(dependent_variable ~ fixed_factor + (1|random_factor), data=data_frame)
Repeated Measures ANOVA Examines changes in means over time or repeated measurements within the same subjects. Assumes correlated observations, allowing the assessment of how a factor influences the dependent variable over multiple measurements. aov(dependent_variable ~ factor + Error(subject/factor), data=data_frame)

Applications of ANOVA

ANOVA can be used for various purposes, such as:

  • Comparing the means of different groups and testing hypotheses about their differences
  • Exploring the effects of other factors and their interactions on the response variable
  • Evaluating the significance of the factors and their levels on the response variable
  • Assessing the assumptions of ANOVA and checking the validity of the results
  • Performing additional analyses, such as pairwise comparisons, post-hoc tests, effect

Assumptions of ANOVA

Before performing ANOVA, it is important to check whether the assumptions of ANOVA are met. The assumptions of ANOVA are:

  • The outcome variable is continuous and normally distributed within each group.
  • The variance of the outcome variable is equal across all groups.
  • The observations are independent and randomly sampled from the population.
If these assumptions are violated, the results of ANOVA may not be valid or reliable. Therefore, it is recommended that diagnostic checks be performed to verify the assumptions of ANOVA in R.
Assumption Diagnostic Check R Code Example
Normality of Residuals Visual inspection of Q-Q plots or histograms qqnorm(resid(result))
Homogeneity of Variances Examination of residuals across groups plot(result, 1)
Independence of Observations Assessing residuals for patterns or trends plot(result, 2)
Outlier Detection Identification of influential points or outliers plot(result, 3)
Linearity of Relationships Examining residuals against predicted values plot(result, 5)

If the assumptions of ANOVA are not met. In that case, you may need to transform the data, use a different type of ANOVA, or use a non-parametric alternative, such as the Kruskal-Wallis or Mann-Whitney test, to compare the means of the groups. 

Check Assumptions of ANOVA in R

Before we check the assumption of ANOVA in R, we load the data set in RStudio. I will use the PlantGrowth data set in this tutorial in RStudio.  The data set has two variables: weight, which is the outcome variable, and light, which is the factor variable with three levels: ctrl, trt1, and trt2. The data set looks like this:

Load the PlantGrowth data set in R, explore the dataset before check the assumption of anova in R


Check the normality assumption, we can use the hist function to plot the histogram of the weight variable within each light group or the shapiro.test function to perform the Shapiro-Wilk test for normality. 

					# Create individual histograms for each group
par(mfrow = c(1, 3))  # Set the layout to have 1 row and 3 columns
for (grp in levels(PlantGrowth$group)) {
  subset_data <- PlantGrowth[PlantGrowth$group == grp, ]
  hist(subset_data$weight, main = paste("Histogram of", grp), xlab = "Weight", col = "lightblue", border = "black")
par(mfrow = c(1, 1))  # Reset the layout to default

# Create a function to perform Shapiro-Wilk test and extract p-value
shapiro_test_and_pvalue <- function(data) {
  result <- shapiro.test(data)
  p_value <- format(result$p.value, digits = 4)

# Apply the function to each group
shapiro_results <- t(sapply(levels(PlantGrowth$group), function(grp) {
  subset_data <- PlantGrowth$weight[PlantGrowth$group == grp]
  p_value <- shapiro_test_and_pvalue(subset_data)
  return(c(Group = grp, P_Value = p_value))
# Create a data frame from the results
You can also do it using the simple function of hist() or the function from the ggplot2 library.[

The histograms show that the weight variable is approximately normally distributed within each light group, and the p-values of the Shapiro-Wilk tests are all greater than 0.05, meaning we cannot reject the null hypothesis that the weight variable is normally distributed within each light group. Therefore, we can assume that the normality assumption is met.

Homogeneity of variance

We can use the boxplot function to plot the boxplot of the weight variable within each light group or the leveneTest function from the car package to perform Levene’s test for homogeneity of variance. 

# Boxplot to visualize the distribution of weights across groups
boxplot(weight ~ group, data = PlantGrowth, col = c("#999999", "#E69F00", "#56B4E9"),
        main = "Boxplot of Plant Growth by Group",
        xlab = "Group", ylab = "Weight")

# Load required library
# Levene's test for homogeneity of variances
leveneTest(weight ~ group, data = PlantGrowth)
boxplot by using the boxplot() function of R, that was builtin function of R to check the Homogeneity of variance

The boxplot shows that the weight variable has similar ranges and shapes within each light group, and the p-value of Levene’s test is greater than 0.05, meaning we cannot reject the null hypothesis that the weight variable has equal variance across all light groups. Therefore, we can assume that the homogeneity of variance assumption is met.


To check the independence assumption, we can use common sense or domain knowledge to assess whether the observations are independent and randomly sampled from the population. For example, if we know that the plants were grown in separate pots and randomly assigned to different light conditions, we can assume that the independence assumption is met.

Handling data input and preprocessing for ANOVA in R

Attention to input and preprocessing is vital in preparing data for ANOVA in R. 
  • Begin by importing data, ensuring it aligns with the study's design. 
  • Validate variable types and handle any missing values. 
  • Grouping factors, often categorical, require encoding for effective analysis. 
  • Explore distributions through descriptive statistics and visualizations, detecting outliers or skewed data that may impact results. 
  • Normalize or transform variables if needed for assumptions. 
  • Employ consistent naming conventions and organize data structures systematically. 

Performing one-way ANOVA in R


The research question we want to answer using one-way ANOVA is:
Is there a significant difference in the mean weight of plants grown under different light conditions?

Dont know how to write a hypothesis effectively? 

Load the data 

In this tutorial, we will be using a built-in data set, but if you want to use your own data set, you can read the data set by using the read.csv function, which reads a comma-separated values file and returns a data frame. For example, if the data file is called plant_growth.csv and is stored in the current working directory:

						plant_growth <- read.csv("plant_growth.csv")

Perform the ANOVA using the aov function

To perform one-way ANOVA using the aov function and display the ANOVA table using the summary function. To perform one-way ANOVA in R:

aov(weight ~ group, data = PlantGrowth)
summary(aov(weight ~ group, data = PlantGrowth))

The ANOVA table shows that the variation between groups is 3.766, the variation within groups (residuals) is 10.492, the mean square between groups is 1.8832, the mean square within groups is 0.3886, the F-statistic is 4.846, and the p-value is 0.01591. How to make a decision based on P-value read this.

The p-value is less than 0.05, so the null hypothesis that the mean weight is the same for all groups is rejected. Therefore, we can conclude that there is a significant difference in the mean weight among the three groups.

Performing two-way ANOVA in R

To perform two-way ANOVA in R using the data set, I will use ToothGrowth, which contains the measurements of the length of odontoblasts (cells responsible for tooth growth) in 60 guinea pigs. 

Load the data

The data set has three variables: len, the outcome variable, supp, and dose, the factor variables with two and three levels, respectively. The supp variable indicates the supplement type (VC or OJ), and the dose variable indicates the dose level (0.5, 1, or 2 mg). The data set looks like this:



The research question we want to answer using two-way ANOVA is: 

Is there a significant difference in the mean length of odontoblasts among the different combinations of supplement type and dose level?  

Two-way ANOVA in R

To perform two-way ANOVA using the aov function and display the ANOVA table using the summary function.
summary(aov(len ~ supp * dose, data = ToothGrowth))
Two way anova by using the toothgrowth data set in Rstudio

The ANOVA table shows that the variation due to supp is 205.35, the variation due to dose is 2426.43, the variation due to supp and dose interaction is 88.9, and the variation due to residuals is 933.6. The mean square due to supp is 205.35, the mean square due to dose is 2224.3, the mean square due to supp and dose interaction is 88.9, and the mean square due to residuals is 16.7. 

The F-statistic value due to supp is 12.317, the dose (133.415), supp and dose interaction (5.333), and the p-value due to supp is 0.000894, dose (<2e-16), supp and dose interaction (0.0246). The p-values are all less than 0.05, which means that the null hypotheses that the mean len is the same for all levels of supp, dose, and supp and dose interaction are rejected. 

Therefore, we can conclude that there are significant main effects of supp and dose and a significant interaction effect of supp and dose on the len of the odontoblasts.

Examining the ANOVA results and assessing the significance

Post Hoc Test

A post hoc test is employed after ANOVA to identify specific group differences when the overall ANOVA result indicates statistical significance read more. It can pinpoint which groups differ. It provides a more detailed understanding of differences within the data set. The post hoc tests help avoid potential Type I errors. They also enhance the precision of multiple comparisons in statistical analyses.

Post Hoc Test Description When to Use R Code Example
Tukey's HSD Determines pairwise differences between group means, effective when the number of groups is unequal. Ideal for comparing means when conducting multiple pairwise comparisons, especially after ANOVA. TukeyHSD(aov_result)
Bonferroni Correction Adjusts significance levels for multiple comparisons to control the familywise error rate. Suitable when making several comparisons to maintain an overall desired level of significance. pairwise.t.test(data$dependent_variable, data$group, p.adj = "bonferroni")
Scheffé's Method Offers a balance between sensitivity and stringency in detecting differences among group means. Appropriate when the assumption of homogeneity of variances is not met and the number of groups is equal. ScheffeTest(aov_result)
Games-Howell Addresses unequal variances and sample sizes, providing robust pairwise comparisons. Useful when assumptions of homogeneity of variances and equal sample sizes are violated. posthocGamesHowell(aov_result)
Dunnett's Test Compares each group mean to a control group mean, suitable for one-way ANOVA with a control group. Effective when there is a designated control group, and the interest lies in comparing other groups to this control. DunnettTest(aov_result, "ControlGroup")

Using Tukey's HSD test for One way ANOVA in R

One of the most common post-hoc tests is Tukey’s HSD test, which stands for honestly significant difference. Tukey’s HSD test can be performed in R using the TukeyHSD function, which takes an object of class “aov” as an argument. 

TukeyHSD(aov(weight ~ group, data = PlantGrowth))

In plant growth, the analysis of variance (ANOVA) results show significant variations among at least one pair of groups. The Tukey HSD post hoc test compares group means, revealing a significant difference (p = 0.012) between trt2 and trt1, suggesting distinct effects on weight. 

However, no significant differences were observed between trt1 and ctrl (p = 0.391) or trt2 and ctrl (p = 0.198). The confidence intervals for the group differences (diff) provide a range for the true mean differences, aiding in result interpretation.These findings add to our understanding of how different treatments affect plant growth.

Tukey's HSD Test for Two way ANOVA in R

The ANOVA results show that the supp, dose, and supp and dose interaction factors significantly affect the len of the odontoblasts. Still, they do not tell us which specific levels or combinations differ. To find out which levels or combinations of levels have significantly different means, we need to perform a post-hoc test.

ToothGrowth$dose <- as.factor(ToothGrowth$dose)
TukeyHSD(aov(len ~ supp * dose, data = ToothGrowth))

The Tukey multiple comparisons for ToothGrowth's length ('len') reveal significant differences. In 'supp,' the VC-OJ difference is -3.7 (p = 0.0002), indicating varied effects of supplements on length. Regarding 'dose,' substantial differences exist between each level (p < 0.001), emphasizing dose impact.

The interaction 'supp:dose' unveils intricate patterns, e.g., OJ:1 vs. OJ:0.5 (diff = 9.47, p = 0.0000046), elucidating nuanced effects when combining supplement and dose. These findings provide detailed insights into the factors influencing tooth length, supporting precise conclusions for experimental conditions and guiding further investigation.

Other types of ANOVA in R

Univariate ANOVA in R

When you have one dependent variable and one independent variable with two or more groups, you utilize Univariate ANOVA. 

#Generate a dataset for replicated ANOVA
set.seed(123)  # Set a seed for reproducibility
# Generate synthetic dataset
subject <- factor(rep(1:20, 3))  # Replicated subject IDs
independent_variable <- factor(rep(c("Group 1", "Group 2", "Group 3"), each = 20))
dependent_variable <- c(rnorm(60, mean = 10, sd = 2))
replicated_data <- data.frame(subject, independent_variable, dependent_variable)
Anova(lm(dependent_variable ~ independent_variable, data = replicated_data))

Multivariate ANOVA

Multivariate ANOVA (MANOVA) is an extension of univariate ANOVA that allows for the simultaneous analysis of many dependent variables. 

# Load the 'iris' dataset
# Fit a MANOVA model
manova_model <- manova(cbind(Sepal.Length, Sepal.Width, Petal.Length, Petal.Width) ~ Species, data = iris)
# Display the MANOVA results

ANOVA with Replication

ANOVA with replication is used when there is just one dependent variable and one independent variable. Still, measurements are obtained from the same participants at different periods or situations. 

# Set seed for reproducibility
# Number of observations per group
num_obs <- 200
# Create a replicated dataset
replicated_data <- data.frame(
  Group = rep(letters[1:3], each = num_obs),
  Factor1 = rep(LETTERS[1:2], each = num_obs * 3),
  Factor2 = rep(1:2, each = num_obs * 3),
  Dependent_Variable = rnorm(num_obs * 3, mean = 50, sd = 10)
# Perform ANOVA with replication
summary(aov(Dependent_Variable ~ Factor1 * Factor2 + Error(Group), data = replicated_data))

Factorial ANOVA

Factorial ANOVA is utilized when there are two or more independent variables and one dependent variable. It aids in determining the significant impacts of each independent variable and their interactions with the dependent variable. Here's an example of using factorial ANOVA in R:

summary(aov(Dependent_Variable ~ Factor1 * Factor2 + Group, data = replicated_data))

Common Issues and Solutions in ANOVA and R Programming

Data Analysts often encounter common challenges while performing ANOVA in R programming due to complex data or models. Issues may arise from data consistency, outliers, or violations of assumptions. However, these challenges are manageable. 

Rigorous data preprocessing, identification, removal of outliers, and ensuring assumptions like normality and homogeneity of variances are met contribute to robust ANOVA analyses. Attention to detail during the data preparation and judicious handling of anomalies are pivotal for successful implementation.

Troubleshooting Common Errors When Performing ANOVA in R

Performing ANOVA in R may encounter syntax, data format errors, or inadequate understanding of R's functions. Addressing these errors involves careful code review, debugging, and ensuring compatibility between the dataset and ANOVA functions.

Resolving Problems Related to Meeting ANOVA Assumptions in R

ANOVA assumes certain conditions like normality and homogeneity of variances. Deviations from these assumptions can compromise the validity of results. In R, addressing these challenges involves

  • employing statistical tests for normality,
  • transforming variables if needed, and
  • exploring robust alternatives when assumptions are violated.

Adhering to best practices in handling assumptions enhances the reliability and accuracy of ANOVA outcomes in R.

Addressing Challenges in Interpreting ANOVA Results and Statistical Tests in R

Interpreting ANOVA results in R requires a nuanced grasp of statistical concepts. Challenges in deciphering p-values, understanding effect sizes, and post-hoc test outcomes may arise. Through concise and clear explanations, alongside graphical representations, the interpretation process becomes more accessible. 

They emphasize effect size measures and consider practical significance aids in comprehensively understanding ANOVA outcomes in the R environment.

Dealing with Handling Categorical Data and Factors in ANOVA within R

ANOVA in R involves handling categorical data and factors effectively. Challenges may arise in appropriately encoding categorical variables and understanding their impact on ANOVA results. 

Proper variable transformation, categorical encoding techniques, and careful consideration of factor levels ensure accurate representation in the analysis. Mastery over the intricacies of categorical data handling in R enhances the precision of ANOVA outcomes.

Optimizing ANOVA Test Setup and Execution in R Programming

Efficient setup and execution of ANOVA tests in R demand meticulous planning. Optimizing the choice of ANOVA type, selecting appropriate experimental designs, and streamlining code execution contribute to enhanced efficiency. 

Leveraging R's capabilities for parallel processing, adopting tidy data principles, and utilizing built-in functions lead to a seamless ANOVA workflow. Striking a balance between computational efficiency and statistical rigor ensures optimal ANOVA test implementation in R programming.


This article will teach us about ANOVA implementation in R using real-world data sets. ANOVA, classified into types like one-way and two-way ANOVA, compares means across different factor levels. R's `aov` function performs ANOVA, while `summary` displays the ANOVA table. 

Post-hoc tests, executed by `TukeyHSD`, compare means and show differences, confidence intervals, and adjusted p-values. ANOVA proves invaluable for hypothesis testing, effect evaluation, and drawing variable relationships, offering a comprehensive understanding through this tutorial.

Frequently Asked Questions (FAQs)

How to interpret ANOVA results in R?

Examine the p-value in the ANOVA table; a small p-value indicates significant differences among group means.

How to read an ANOVA table?

Focus on the F-statistic and its associated p-value; low p-values suggest significant differences.

Can you use one-way ANOVA for two groups?

Yes, but a t-test is more appropriate for precisely comparing two groups.

How to analyze ANOVA results?

Look for significant differences via p-values; if found, proceed to post hoc tests for specific group comparisons.

How to graph ANOVA results?

Create boxplots or interaction plots to visually represent group differences.

How to run repeated measures ANOVA in R?

Employ the aov function with a repeated measures design or consider the ezANOVA function from the ez package.

How to get p-value from ANOVA in R?

Access the p-value directly from the ANOVA table using summary(result)$'Pr(>F)'.

What is R-squared in ANOVA?

R-squared in ANOVA, known as eta-squared (eta_squared), measures the proportion of total variance the model explains.

How to do two-way ANOVA without replication in R?

Use the aov function with the formula Y ~ A * B for main effects and interaction without replication.

How to format data for ANOVA in R?

Organize data with a column for the dependent variable and one or more columns for the independent variables.

How to calculate ANOVA without built-in functions in R?

Compute the ANOVA manually by calculating sums of squares and using appropriate formulas.

What is R-value in ANOVA?

There is no direct "R-value" in ANOVA. You may mean R-squared (eta_squared), representing the variance explained.

How can you do ANOVA in R without using the function?

Manually calculate ANOVA by obtaining sums of squares and degrees of freedom and applying the appropriate formulas.

How to run Shapiro test in R for three-way ANOVA?

Use shapiro.test on the residuals of the ANOVA model: shapiro.test(result$residuals).

Why is DF not calculated correctly in R for ANOVA?

Ensure data is correctly formatted and variables are factors. Check for missing values that may affect degrees of freedom.

How to set up Excel data for one-way ANOVA in R Studio?

Organize data with a column for the dependent variable and a separate column for the grouping factor. Save as a CSV file and import into R.

Which post hoc tests are different in R ANOVA?

Common post hoc tests in R include Tukey's HSD (TukeyHSD), Bonferroni (pairwise.t.test), and Dunnett's test (DunnettTest).

How to calculate sample size for repeated measures ANOVA in R?

Consider power analysis using functions like pwr.anova.test from the pwr package.

In which R package is ANOVA?

The base R package contains the above function for ANOVA and additional packages like car and ez offer extended functionalities.

How to predict with ANOVA in R?

After fitting an ANOVA model, use predict to obtain predicted values for new data points.

Do you need help with a data analysis project? Let me assist you! With a PhD and ten years of experience, I specialize in solving data analysis challenges using R and other advanced tools. Reach out to me for personalized solutions tailored to your needs.

About the Author

Ph.D. Scholar | Certified Data Analyst | Blogger | Completed 5000+ data projects | Passionate about unravelling insights through data.

Post a Comment

RStudiodataLab Chatbot
Have A Question?We will reply within minutes
Hello, how can we help you?
Start chat...
Cookie Consent
We serve cookies on this site to analyze traffic, remember your preferences, and optimize your experience.
It seems there is something wrong with your internet connection. Please connect to the internet and start browsing again.