FRIEDMANCHISQUARE
Overview
The FRIEDMANCHISQUARE function performs the Friedman test, a non-parametric statistical test used to detect differences across multiple test attempts (treatments) in repeated measures designs. Developed by economist Milton Friedman, this test serves as a non-parametric alternative to the parametric repeated measures ANOVA when the assumption of normality cannot be met.
The Friedman test is particularly useful for analyzing ranked data from randomized complete block designs. Classic applications include comparing multiple wine ratings from the same judges, evaluating different treatments on the same subjects, or assessing whether machine learning classifiers perform consistently differently across multiple datasets.
The test works by ranking observations within each block (row) and then analyzing the consistency of rankings across treatments (columns). Given data \{x_{ij}\}_{n \times k} with n blocks and k treatments, the algorithm:
- Ranks observations within each block to produce ranks r_{ij}
- Computes the mean rank for each treatment: \bar{r}_{\cdot j} = \frac{1}{n}\sum_{i=1}^{n} r_{ij}
- Calculates the test statistic:
Q = \frac{12n}{k(k+1)} \sum_{j=1}^{k} \left( \bar{r}_{\cdot j} - \frac{k+1}{2} \right)^2
The statistic Q follows a chi-squared distribution with k-1 degrees of freedom when n or k is sufficiently large (typically n > 10 and k > 4). This implementation uses SciPy’s friedmanchisquare function, which returns both the test statistic (corrected for ties) and the associated p-value. For more details on the algorithm, see the SciPy GitHub repository.
Related tests include the Kruskal-Wallis test for independent samples and the Wilcoxon signed-rank test for comparing only two related groups. For additional background, see the Friedman test on Wikipedia.
This example function is provided as-is without any representation of accuracy.
Excel Usage
=FRIEDMANCHISQUARE(samples)
samples(list[list], required): 2D array where each column represents a repeated measurement group. Must have at least three columns.
Returns (list[list]): 2D list [[statistic, p_value]], or error message string.
Examples
Example 1: Demo case 1
Inputs:
| samples | ||
|---|---|---|
| 10 | 20 | 30 |
| 20 | 20 | 20 |
| 30 | 10 | 20 |
Excel formula:
=FRIEDMANCHISQUARE({10,20,30;20,20,20;30,10,20})
Expected output:
| Result | |
|---|---|
| 0.2 | 0.9048 |
Example 2: Demo case 2
Inputs:
| samples | |||
|---|---|---|---|
| 10 | 20 | 30 | 40 |
| 20 | 20 | 20 | 20 |
| 30 | 10 | 20 | 30 |
| 40 | 30 | 20 | 10 |
Excel formula:
=FRIEDMANCHISQUARE({10,20,30,40;20,20,20,20;30,10,20,30;40,30,20,10})
Expected output:
| Result | |
|---|---|
| 1.1143 | 0.7736 |
Example 3: Demo case 3
Inputs:
| samples | ||
|---|---|---|
| 2 | 5 | 8 |
| 3 | 6 | 7 |
| 1 | 4 | 9 |
| 4 | 7 | 6 |
| 5 | 3 | 5 |
Excel formula:
=FRIEDMANCHISQUARE({2,5,8;3,6,7;1,4,9;4,7,6;5,3,5})
Expected output:
| Result | |
|---|---|
| 1.3333 | 0.8557 |
Example 4: Demo case 4
Inputs:
| samples | ||
|---|---|---|
| 5 | 10 | 15 |
| 10 | 5 | 10 |
| 15 | 10 | 5 |
Excel formula:
=FRIEDMANCHISQUARE({5,10,15;10,5,10;15,10,5})
Expected output:
| Result | |
|---|---|
| 0.5455 | 0.7613 |
Python Code
from scipy.stats import friedmanchisquare as scipy_friedmanchisquare
import math
def friedmanchisquare(samples):
"""
Computes the Friedman test for repeated samples.
See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.friedmanchisquare.html
This example function is provided as-is without any representation of accuracy.
Args:
samples (list[list]): 2D array where each column represents a repeated measurement group. Must have at least three columns.
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 samples or not all(isinstance(col, list) for col in samples):
return "Invalid input: samples must be a 2D list with at least three columns."
n_cols = len(samples)
if n_cols < 3:
return "Invalid input: samples must have at least three columns (samples)."
n_rows = [len(col) for col in samples]
if len(set(n_rows)) != 1:
return "Invalid input: all columns must have the same number of rows."
if n_rows[0] < 2:
return "Invalid input: each column must have at least two rows."
for col in samples:
for val in col:
if not isinstance(val, (int, float)):
return "Invalid input: all values must be numeric."
try:
args = [list(col) for col in samples]
stat, pvalue = scipy_friedmanchisquare(*args)
stat = float(stat)
pvalue = float(pvalue)
if math.isnan(stat) or math.isnan(pvalue) or math.isinf(stat) or math.isinf(pvalue):
return "Invalid output: statistic or pvalue is nan or inf."
return [[stat, pvalue]]
except Exception as e:
return f"scipy.stats.friedmanchisquare error: {e}"