LEVENE
Overview
The LEVENE function performs Levene’s test for equality of variances (also called homogeneity of variance) across two or more sample groups. This test is commonly used to verify the equal variance assumption required by statistical procedures such as ANOVA and t-tests. Levene’s test is a robust alternative to the Bartlett test, as it is less sensitive to departures from normality in the underlying data.
The test was originally proposed by Howard Levene in 1960, and later extended by Brown and Forsythe (1974) to include median and trimmed mean variants. The null hypothesis states that all population variances are equal (\sigma_1^2 = \sigma_2^2 = \ldots = \sigma_k^2), while the alternative hypothesis states that at least one pair of variances differs.
The test statistic W is computed as:
W = \frac{(N-k)}{(k-1)} \cdot \frac{\sum_{i=1}^{k} N_i (\bar{Z}_{i\cdot} - \bar{Z}_{\cdot\cdot})^2}{\sum_{i=1}^{k} \sum_{j=1}^{N_i} (Z_{ij} - \bar{Z}_{i\cdot})^2}
where Z_{ij} = |Y_{ij} - \tilde{Y}_i| represents the absolute deviation of each observation from the group’s central tendency measure, N is the total sample size, k is the number of groups, and N_i is the sample size of group i.
This implementation uses SciPy’s levene function and supports three center options for computing deviations: median (recommended for skewed distributions), mean (best for symmetric, moderate-tailed distributions), and trimmed mean (optimal for heavy-tailed distributions). The median-based variant, often called the Brown-Forsythe test, is the default as it provides good robustness across many data types. For additional background, see the NIST Engineering Statistics Handbook.
This example function is provided as-is without any representation of accuracy.
Excel Usage
=LEVENE(samples, levene_center, trimmed_proportion)
samples(list[list], required): 2D list where each inner list is a sample group to compare.levene_center(str, optional, default: “median”): Central tendency function for computing deviations.trimmed_proportion(float, optional, default: null): Proportion to cut from each end when center is ‘trimmed’. Must be in [0, 0.5).
Returns (list[list]): 2D list [[statistic, p_value]], or error message string.
Examples
Example 1: Basic case with median center
Inputs:
| samples | levene_center | ||
|---|---|---|---|
| 1.2 | 2.3 | 2.1 | median |
| 2.5 | 2.7 | 2.8 | |
| 1.9 | 2 | 2.2 |
Excel formula:
=LEVENE({1.2,2.3,2.1;2.5,2.7,2.8;1.9,2,2.2}, "median")
Expected output:
| Result | |
|---|---|
| 0.8767 | 0.4634 |
Example 2: Mean center variant
Inputs:
| samples | levene_center | ||
|---|---|---|---|
| 1.2 | 2.3 | 2.1 | mean |
| 2.5 | 2.7 | 2.8 | |
| 1.9 | 2 | 2.2 |
Excel formula:
=LEVENE({1.2,2.3,2.1;2.5,2.7,2.8;1.9,2,2.2}, "mean")
Expected output:
| Result | |
|---|---|
| 5.8824 | 0.0385 |
Example 3: Trimmed center with 0.1 proportion
Inputs:
| samples | levene_center | trimmed_proportion | ||
|---|---|---|---|---|
| 1.2 | 2.3 | 2.1 | trimmed | 0.1 |
| 2.5 | 2.7 | 2.8 | ||
| 1.9 | 2 | 2.2 |
Excel formula:
=LEVENE({1.2,2.3,2.1;2.5,2.7,2.8;1.9,2,2.2}, "trimmed", 0.1)
Expected output:
| Result | |
|---|---|
| 5.8824 | 0.0385 |
Example 4: Groups with equal variances
Inputs:
| samples | levene_center | ||
|---|---|---|---|
| 1 | 1.1 | 1.2 | median |
| 2 | 2.1 | 2.2 | |
| 3 | 3.1 | 3.2 |
Excel formula:
=LEVENE({1,1.1,1.2;2,2.1,2.2;3,3.1,3.2}, "median")
Expected output:
| Result | |
|---|---|
| 0 | 1 |
Python Code
import math
from scipy.stats import levene as scipy_levene
def levene(samples, levene_center='median', trimmed_proportion=None):
"""
Performs the Levene test for equality of variances across multiple samples.
See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.levene.html
This example function is provided as-is without any representation of accuracy.
Args:
samples (list[list]): 2D list where each inner list is a sample group to compare.
levene_center (str, optional): Central tendency function for computing deviations. Valid options: Median, Mean, Trimmed. Default is 'median'.
trimmed_proportion (float, optional): Proportion to cut from each end when center is 'trimmed'. Must be in [0, 0.5). Default is None.
Returns:
list[list]: 2D list [[statistic, p_value]], or error message string.
"""
def to2d(x):
return [[x]] if not isinstance(x, list) else x
samples = to2d(samples)
if not isinstance(samples, list) or not all(isinstance(g, list) for g in samples):
return "Invalid input: samples must be a 2D list."
if len(samples) < 2:
return "Invalid input: samples must contain at least two groups."
if any(len(g) < 2 for g in samples):
return "Invalid input: each sample group must have at least two values."
valid_centers = ('mean', 'median', 'trimmed')
if levene_center not in valid_centers:
return f"Invalid input: levene_center must be one of {valid_centers}."
if levene_center == 'trimmed':
if trimmed_proportion is None:
return "Invalid input: trimmed_proportion required when center is 'trimmed'."
try:
trimmed_proportion = float(trimmed_proportion)
except (TypeError, ValueError):
return "Invalid input: trimmed_proportion must be a number."
if not (0 <= trimmed_proportion < 0.5):
return "Invalid input: trimmed_proportion must be in [0, 0.5)."
try:
samples_float = [[float(x) for x in g] for g in samples]
except (TypeError, ValueError):
return "Invalid input: all sample values must be numeric."
try:
if levene_center == 'trimmed':
result = scipy_levene(*samples_float, center=levene_center, proportiontocut=trimmed_proportion)
else:
result = scipy_levene(*samples_float, center=levene_center)
stat, pvalue = float(result.statistic), float(result.pvalue)
except Exception as e:
return f"Levene test error: {e}"
if math.isnan(stat) or math.isinf(stat) or math.isnan(pvalue) or math.isinf(pvalue):
return "Invalid output: statistic or pvalue is NaN or infinite."
return [[stat, pvalue]]