Converting test statistics to partial eta square from ANOVA - Private-Projects237/Statistics GitHub Wiki

Overview

This wiki page will serve as a reference to transform test statistics into partial eta square.

What is partial-eta squared?

This is an effect size that measures how much of the variance is explained by a main effect or interaction after controlling for the effects of the other predictors in the model. This is the preferred approach to report effect sizes, unlike eta-square.


\eta_p^2 = \frac{SS_{effect}}{SS_{effect} + SS_{error}}

How would you calculate partial eta-squared in R?

You can do it by hand by using the formula from above. When you run an ANOVA model, use the summary() function to produce the sum of squares, degrees of freedom, the mean square values, the F statistic and the corresponding p-value of the main/interaction effects. Use that information to calculate eta-squared. If you are scared of making a mistake you could use the eta_squared() function on the model from the 'effectsize' package. By default this function will return partial eta squared.

How to calculate partial eta square from the F-statistic and degrees of freedom?

In many cases you will not have the information from the sum of squares to calculate partial eta square in the traditional way. Luckily, you can calculate this from the F-statistic and degrees of freedom of the corresponding effect. This is what the equation looks like.

\eta_p^2 = \frac{F \times df_{effect}}{F \times df_{effect} + df_{error}}

Calculate Partial Eta-Squared from F-statistic and Degrees of Freedom Custom Function

  • Use this for calculating partial eta-squared from tests statistics reported in papers. This should help with reporting effect sizes when writing a manuscript or doing a meta.
# Create a custom function
Partial_eta_s_from_f_and_df <- function(f_stat, df_effect, df_error){
  (f_stat * df_effect)/(f_stat * df_effect + df_error)
}

Example 1 in R (one-way ANOVA)

Generate the data and run a one-way ANOVA

# Set seed
set.seed(123)

# Create a factor with 3 groups
group <- factor(rep(c("A", "B", "C"), each = 30))

# Generate data with different means
value <- c(
  rnorm(30, mean = 50, sd = 10),
  rnorm(30, mean = 55, sd = 10),
  rnorm(30, mean = 60, sd = 10)
)

# Combine into a data frame
data <- data.frame(group, value)

# get to know our data
summary(data)

# run the model
anova_model <- aov(value ~ group, data = data)
(anova_table <- summary(anova_model)[1](/Private-Projects237/Statistics/wiki/1))

Calculate partial eta-square by hand

# Calculate partial eta-square 
SS_effect <- anova_table["group","Sum Sq"]
SS_error <- anova_table["Residuals","Sum Sq"]
(partial_eta_sq <- SS_effect / (SS_effect + SS_error))

Calculate partial eta-square using a built in function

# Confirm eta-square was calculate correctly
library(effectsize)
eta_squared(anova_model)

Calculate partial eta-square from the F statistic and degrees of freedom

# Calculate partial eta-square (from F statistic)
f_stat <- anova_table["group","F value"]
df_effect <- anova_table["group","Df"]
df_error <- anova_table["Residuals","Df"]
(partial_eta_sq_f <- (f_stat * df_effect)/(f_stat * df_effect + df_error))

Compare the eta square from the different approaches

R Code Output for Partial Eta-Squared Calculations
Screenshot 2025-04-19 at 9 11 18 PM

Example 2 in R (two-way ANOVA)

Generate the data and run a two-way ANOVA

# Set seed
set.seed(123)

# Factor A: 2 levels
factorA <- factor(rep(c("Control", "Treatment"), each = 90))

# Factor B: 3 levels, repeated within each level of A
factorB <- factor(rep(c("Low", "Medium", "High"), each = 30, times = 2))

# Simulate outcome variable
# Slightly different means for each group combination
value <- c(
  rnorm(30, mean = 50, sd = 10),  # Control - Low
  rnorm(30, mean = 52, sd = 10),  # Control - Medium
  rnorm(30, mean = 54, sd = 10),  # Control - High
  rnorm(30, mean = 55, sd = 10),  # Treatment - Low
  rnorm(30, mean = 60, sd = 10),  # Treatment - Medium
  rnorm(30, mean = 65, sd = 10)   # Treatment - High
)

# Combine into data frame
data <- data.frame(factorA, factorB, value)

# Run the model
anova_model <- aov(value ~ factorA * factorB, data = data)
(anova_table <- summary(anova_model)[1](/Private-Projects237/Statistics/wiki/1))
row.names(anova_table) <- gsub("\\s+", "", rownames(anova_table)) # Fix row names

(Optional) Visualize the Main and Interaction Effects

# Visualizing the main effects (Optional)
data %>%
  ggplot(aes(x= factorA, y = value)) +
  stat_summary(fun = "mean", geom = "point") +
  stat_summary(fun.data = mean_cl_boot, geom = "errorbar", width = .2) +
  theme_classic()

data %>%
  ggplot(aes(x= factorB, y = value)) +
  stat_summary(fun = "mean", geom = "point") +
  stat_summary(fun.data = mean_cl_boot, geom = "errorbar", width = .2) +
  theme_classic()

data %>%
  ggplot(aes(x= factorA, y = value, color = factorB)) +
  stat_summary(fun = "mean", geom = "point", position = position_dodge(width = .3)) +
  stat_summary(fun.data = mean_cl_boot, geom = "errorbar", position = position_dodge(width = .3), width = .2) +
  theme_classic()
Factor A Main Effect Factor B Main Effect Factor A x Factor B Interaction
Screenshot 2025-04-19 at 9 45 41 PM Screenshot 2025-04-19 at 9 45 55 PM Screenshot 2025-04-19 at 9 46 08 PM

Calculate partial eta-square by hand

# Calculate partial eta-square 
SS_effect1 <- anova_table["factorA","Sum Sq"]
SS_error1 <- anova_table["Residuals","Sum Sq"]
(partial_eta_sq1 <- SS_effect1 / (SS_effect1 + SS_error1))

SS_effect2 <- anova_table["factorB","Sum Sq"]
SS_error2 <- anova_table["Residuals","Sum Sq"]
(partial_eta_sq2 <- SS_effect2 / (SS_effect2 + SS_error2))

SS_effect3 <- anova_table["factorA:factorB","Sum Sq"]
SS_error3 <- anova_table["Residuals","Sum Sq"]
(partial_eta_sq3 <- SS_effect3 / (SS_effect3 + SS_error3))

Calculate partial eta-square using a built in function

# Confirm eta-square was calculate correctly
library(effectsize)
eta_squared(anova_model)

Calculate partial eta-square from the F statistic and degrees of freedom

# Calculate partial eta-square (from F statistic)
f_stat1 <- anova_table["factorA","F value"]
df_effect1 <- anova_table["factorA","Df"]
df_error1 <- anova_table["Residuals","Df"]
(partial_eta_sq_f1 <- (f_stat1 * df_effect1)/(f_stat1 * df_effect1 + df_error1))

f_stat2 <- anova_table["factorB","F value"]
df_effect2 <- anova_table["factorB","Df"]
df_error2 <- anova_table["Residuals","Df"]
(partial_eta_sq_f2 <- (f_stat2 * df_effect2)/(f_stat2 * df_effect2 + df_error2))

f_stat3 <- anova_table["factorA:factorB","F value"]
df_effect3 <- anova_table["factorA:factorB","Df"]
df_error3 <- anova_table["Residuals","Df"]
(partial_eta_sq_f3 <- (f_stat3 * df_effect3)/(f_stat3 * df_effect3 + df_error3))

Compare the eta square from the different approaches

R Code Output for Partial Eta-Squared Calculations
Screenshot 2025-04-19 at 9 43 11 PM

Example 3 in R (three-way ANOVA)

Calculate partial eta-square by hand

# Calculate partial eta-square (Use a for loop and custom function)
Partial_eta_s_from_ss <- function(ss_effect, ss_error){
  ss_effect / (ss_effect + ss_error)}
  
ANOVA_row_names <- row.names(anova_table)
all_partial_eta_squared_list <- list()

for(ii in 1:7) {
  
  # Extract current SS and the error SS
  current_SS <- anova_table[ANOVA_row_names[ii],"Sum Sq"]
  error_SS <- anova_table["Residual","Sum Sq"]

  # Calculate partial eta-squared
  all_partial_eta_squared_list[ii](/Private-Projects237/Statistics/wiki/ii) <- Partial_eta_s_from_ss(current_SS,error_SS)

}

# Print our the results
(df1 <- data.frame(effect = ANOVA_row_names[1:7],
           partial_eta_squared = round(do.call(c, all_partial_eta_squared_list),3)))

Calculate partial eta-square using a built in function

# Confirm eta-square was calculate correctly
library(effectsize)
eta_squared(anova_model)

Calculate partial eta-square from the F statistic and degrees of freedom

# Calculate partial eta-square from F-statistic (Use a for loop and custom function)
Partial_eta_s_from_f_and_df <- function(f_stat, df_effect, df_error){
  (f_stat * df_effect)/(f_stat * df_effect + df_error)
}

ANOVA_row_names <- row.names(anova_table)
all_partial_eta_squared_from_F_list <- list()

for(ii in 1:7) {
  
  # Extract current F, df_effect, and df_error
  current_F <- anova_table[ANOVA_row_names[ii],"F value"]
  current_df_effect <- anova_table[ANOVA_row_names[ii],"Df"]
  df_error <- anova_table["Residual","Df"]
  
  # Calculate partial eta-squared
  all_partial_eta_squared_from_F_list[ii](/Private-Projects237/Statistics/wiki/ii) <- Partial_eta_s_from_f_and_df(current_F,current_df_effect,df_error)
  
}

# Print our the results
(df2 <- data.frame(effect = ANOVA_row_names[1:7],
           partial_eta_squared_from_F = round(do.call(c, all_partial_eta_squared_from_F_list),3)))

Compare the eta square from the different approaches

R Code Output for Partial Eta-Squared Calculations
Screenshot 2025-04-19 at 10 09 46 PM