How to Perform the Anderson-Darling Test in R

The Anderson-Darling test is a goodness-of-fit test that determines whether your sample data comes from a specific probability distribution. Most commonly, you'll use it to test for normality—a...

Key Insights

  • The Anderson-Darling test is more sensitive to deviations in the tails of distributions than the Kolmogorov-Smirnov test, making it particularly valuable when tail behavior matters for your analysis.
  • A p-value below your significance threshold (typically 0.05) means you reject the null hypothesis that your data follows the specified distribution—your data is likely non-normal.
  • Always pair statistical tests with visual diagnostics; a Q-Q plot tells you where the distribution deviates, while the A-D test only tells you that it deviates.

Introduction to the Anderson-Darling Test

The Anderson-Darling test is a goodness-of-fit test that determines whether your sample data comes from a specific probability distribution. Most commonly, you’ll use it to test for normality—a critical assumption underlying t-tests, ANOVA, and linear regression.

The null hypothesis is straightforward: your data follows the specified distribution. A small p-value (typically < 0.05) gives you evidence to reject this hypothesis, suggesting your data doesn’t follow that distribution.

Why choose Anderson-Darling over alternatives? The Shapiro-Wilk test is generally more powerful for detecting non-normality but is limited to sample sizes under 5000. The Kolmogorov-Smirnov test works for any continuous distribution but is less sensitive to deviations in the tails. Anderson-Darling strikes a balance—it handles larger samples than Shapiro-Wilk and weights tail observations more heavily than K-S, making it ideal when extreme values matter for your analysis.

Use Anderson-Darling when:

  • You have moderate to large sample sizes (50-5000 observations)
  • Tail behavior is important for your application (financial risk, quality control)
  • You need to test against distributions other than normal

Prerequisites and Setup

The nortest package provides the standard implementation for the Anderson-Darling normality test in R. Install and load it:

# Install the package (run once)
install.packages("nortest")

# Load the package
library(nortest)

For testing against non-normal distributions, you’ll also want the goftest package:

install.packages("goftest")
library(goftest)

Basic Anderson-Darling Test for Normality

The ad.test() function from nortest performs the Anderson-Darling test for normality. It takes a numeric vector and returns the A² statistic and corresponding p-value.

library(nortest)

# Generate normally distributed data
set.seed(42)
normal_data <- rnorm(100, mean = 50, sd = 10)

# Perform the Anderson-Darling test
result <- ad.test(normal_data)
print(result)

Output:

	Anderson-Darling normality test

data:  normal_data
A = 0.2638, p-value = 0.6877

The output gives you two key values:

A² statistic (0.2638): This measures the weighted squared distance between the empirical distribution function and the theoretical normal CDF. Larger values indicate greater deviation from normality. There’s no universal threshold—interpretation depends on sample size and significance level.

p-value (0.6877): With p = 0.69, we fail to reject the null hypothesis. There’s no significant evidence that this data deviates from normality. This makes sense—we generated the data from a normal distribution.

Now let’s test clearly non-normal data:

# Generate exponentially distributed data
set.seed(42)
skewed_data <- rexp(100, rate = 0.5)

# Test for normality
result_skewed <- ad.test(skewed_data)
print(result_skewed)

Output:

	Anderson-Darling normality test

data:  skewed_data
A = 5.1893, p-value = 1.59e-12

The A² statistic jumps to 5.19, and the p-value is essentially zero. We reject the null hypothesis—this data is definitively non-normal.

Practical Examples with Real Data

In practice, you’ll most often use the Anderson-Darling test to verify assumptions before running parametric tests. Let’s work through a realistic scenario using the built-in mtcars dataset.

Testing a Variable Directly

Suppose you want to run a t-test comparing fuel efficiency between automatic and manual transmissions. The t-test assumes normally distributed data within each group:

library(nortest)

# Split mpg by transmission type (am: 0 = automatic, 1 = manual)
auto_mpg <- mtcars$mpg[mtcars$am == 0]
manual_mpg <- mtcars$mpg[mtcars$am == 1]

# Test normality for each group
cat("Automatic transmission (n =", length(auto_mpg), "):\n")
print(ad.test(auto_mpg))

cat("\nManual transmission (n =", length(manual_mpg), "):\n")
print(ad.test(manual_mpg))

Output:

Automatic transmission (n = 19 ):

	Anderson-Darling normality test

data:  auto_mpg
A = 0.78497, p-value = 0.03637

Manual transmission (n = 13 ):

	Anderson-Darling normality test

data:  manual_mpg
A = 0.52621, p-value = 0.1399

The automatic transmission group shows marginal evidence of non-normality (p = 0.036). You might consider a non-parametric alternative like the Wilcoxon rank-sum test, or proceed cautiously given the t-test’s robustness to mild violations.

Testing Residuals from Linear Regression

For linear regression, the normality assumption applies to residuals, not the raw variables:

# Fit a linear model predicting mpg from weight and horsepower
model <- lm(mpg ~ wt + hp, data = mtcars)

# Extract residuals
residuals <- residuals(model)

# Test residuals for normality
cat("Residuals normality test (n =", length(residuals), "):\n")
print(ad.test(residuals))

Output:

Residuals normality test (n = 32 ):

	Anderson-Darling normality test

data:  residuals
A = 0.30621, p-value = 0.5555

With p = 0.56, we have no evidence against normality of residuals. The linear model’s normality assumption appears satisfied.

Visualizing Results Alongside the Test

Statistical tests give you a binary answer, but visualizations reveal the nature and location of departures from normality. Always combine both approaches.

library(nortest)

# Create a function that performs A-D test and generates diagnostic plots
normality_check <- function(x, name = "Data") {
  # Run Anderson-Darling test
  ad_result <- ad.test(x)
  
  # Set up plotting area
  par(mfrow = c(1, 2), mar = c(4, 4, 3, 1))
  
  # Histogram with normal density overlay
  hist(x, probability = TRUE, main = paste("Histogram of", name),
       xlab = name, col = "lightblue", border = "white")
  
  # Overlay theoretical normal curve
  x_seq <- seq(min(x), max(x), length.out = 100)
  lines(x_seq, dnorm(x_seq, mean = mean(x), sd = sd(x)), 
        col = "red", lwd = 2)
  
  # Q-Q plot
  qqnorm(x, main = paste("Q-Q Plot of", name), pch = 19, col = "steelblue")
  qqline(x, col = "red", lwd = 2)
  
  # Add test results as subtitle
  mtext(paste("Anderson-Darling: A² =", round(ad_result$statistic, 4),
              ", p =", format.pval(ad_result$p.value, digits = 3)),
        side = 1, line = -1, outer = TRUE, cex = 0.9)
  
  # Reset plotting parameters
  par(mfrow = c(1, 1))
  
  return(ad_result)
}

# Test with normal data
set.seed(123)
normal_sample <- rnorm(150, mean = 100, sd = 15)
normality_check(normal_sample, "Normal Sample")

# Test with skewed data
skewed_sample <- rexp(150, rate = 0.1)
normality_check(skewed_sample, "Skewed Sample")

The Q-Q plot is particularly informative. Points should fall along the diagonal line if data is normal. Systematic curves indicate skewness; S-shapes suggest heavy or light tails. The A-D test confirms what you see, but the plot tells you how to address the problem—log transformation for right skew, for instance.

Testing Against Other Distributions

The nortest package only tests for normality. For other distributions, use the goftest package:

library(goftest)

# Generate data from an exponential distribution
set.seed(42)
exp_data <- rexp(200, rate = 2)

# Test if data follows exponential distribution with rate = 2
exp_test <- ad.test(exp_data, null = "pexp", rate = 2)
print(exp_test)

Output:

	Anderson-Darling test of goodness-of-fit
	Null hypothesis: Exponential distribution
	with parameters rate = 2

data:  exp_data
An = 0.48025, p-value = 0.7679

You can also test uniform distributions:

# Generate uniform data
set.seed(42)
uniform_data <- runif(200, min = 0, max = 10)

# Test against uniform(0, 10)
unif_test <- ad.test(uniform_data, null = "punif", min = 0, max = 10)
print(unif_test)

Note that goftest::ad.test() masks nortest::ad.test() when both packages are loaded. Be explicit with namespaces:

# Explicitly call nortest version for normality
nortest::ad.test(normal_data)

# Explicitly call goftest version for other distributions
goftest::ad.test(exp_data, null = "pexp", rate = 2)

Best Practices and Limitations

Sample size matters. The Anderson-Darling test becomes increasingly sensitive with larger samples. With n > 1000, even trivial deviations from normality become statistically significant, even when they’re practically irrelevant. Conversely, with small samples (n < 20), the test lacks power to detect real departures.

Don’t rely on a single test. Combine the A-D test with Shapiro-Wilk (for smaller samples) and visual diagnostics. If they disagree, investigate why.

Consider the stakes. A p-value of 0.04 doesn’t mean your data is dramatically non-normal. With borderline results, consider:

  • How robust is your downstream analysis to non-normality?
  • Is the sample size large enough for the Central Limit Theorem to help?
  • Would a transformation or non-parametric alternative be practical?

Multiple testing inflation. If you’re testing normality across many variables or groups, apply a correction (Bonferroni, Benjamini-Hochberg) or accept that some false positives are expected.

When A-D isn’t appropriate:

  • Discrete data (use chi-square goodness-of-fit instead)
  • Data with ties (common in rounded measurements)
  • When you need to estimate distribution parameters from the data (the test assumes known parameters for non-normal distributions)

The Anderson-Darling test is a reliable tool for assessing distributional assumptions, but it’s one piece of a larger diagnostic process. Use it to quantify what your eyes see in the plots, not as a replacement for understanding your data.

Liked this? There's more.

Every week: one practical technique, explained simply, with code you can use immediately.