PAGE_TREND_TEST
Overview
The PAGE_TREND_TEST
function performs Page’s L trend test, a non-parametric statistical test for detecting ordered alternatives across multiple treatments. It is used when you have repeated measures (e.g., ratings or scores) for several treatments and want to test whether there is a monotonic trend (e.g., increasing or decreasing) in the means of the treatments. The test is more powerful than the Friedman test for detecting trends and is especially useful when you have a specific hypothesis about the order of the treatments.
The calculation is based on ranking the data within each subject, summing the ranks for each treatment, multiplying by the predicted ranks, and summing the products to obtain the L statistic:
where is the sum of ranks for treatment and is the predicted rank for treatment . The p-value is computed either exactly or asymptotically, depending on the data size and method.
For more details, see the scipy.stats.page_trend_test documentation .
This example function is provided as-is without any representation of accuracy.
Usage
To use the function in Excel:
=PAGE_TREND_TEST(data, [ranked], [predicted_ranks], [method])
data
(2D list, required): Table of shape (m, n), where each row is a subject and each column is a treatment. Must have at least 2 rows and 3 columns.ranked
(bool, optional, default=False): If True, data is already ranked; otherwise, it will be ranked within each row.predicted_ranks
(2D list or None, optional, default=None): 1-row 2D list of predicted ranks for each treatment. If None, defaults to [1, 2, …, n].method
(str, optional, default=“auto”): Method for p-value calculation: “auto”, “asymptotic”, or “exact”.
The function returns a 1-row 2D list: [L_statistic, p_value, method]
, or an error message (string) if the input is invalid.
Examples
Example 1: Standard Page Trend Test
Inputs:
data | ranked | predicted_ranks | method | ||
---|---|---|---|---|---|
3 | 4 | 3 | FALSE | ||
2 | 2 | 4 | |||
3 | 3 | 5 | |||
1 | 3 | 2 | |||
2 | 3 | 2 | |||
2 | 4 | 5 | |||
1 | 2 | 4 | |||
3 | 4 | 4 | |||
2 | 4 | 5 | |||
1 | 3 | 4 |
Excel formula:
=PAGE_TREND_TEST({3,4,3;2,2,4;3,3,5;1,3,2;2,3,2;2,4,5;1,2,4;3,4,4;2,4,5;1,3,4})
Expected output:
L_statistic | p_value | method |
---|---|---|
133.5 | 0.001819116195 | exact |
This means the L statistic is 133.5 and the p-value is approximately 0.00182 using the exact method.
Example 2: Asymptotic Method
Inputs:
data | ranked | predicted_ranks | method | ||
---|---|---|---|---|---|
3 | 4 | 3 | FALSE | asymptotic | |
2 | 2 | 4 | |||
3 | 3 | 5 | |||
1 | 3 | 2 | |||
2 | 3 | 2 | |||
2 | 4 | 5 | |||
1 | 2 | 4 | |||
3 | 4 | 4 | |||
2 | 4 | 5 | |||
1 | 3 | 4 |
Excel formula:
=PAGE_TREND_TEST({3,4,3;2,2,4;3,3,5;1,3,2;2,3,2;2,4,5;1,2,4;3,4,4;2,4,5;1,3,4}, FALSE, , "asymptotic")
Expected output:
L_statistic | p_value | method |
---|---|---|
133.5 | 0.001269343369 | asymptotic |
Example 3: Data Already Ranked
Inputs:
data | ranked | predicted_ranks | method | ||
---|---|---|---|---|---|
1.5 | 3 | 1.5 | TRUE | ||
1.5 | 1.5 | 3 | |||
1 | 3 | 2 | |||
1.5 | 3 | 1.5 | |||
1 | 2 | 3 | |||
1 | 2.5 | 2.5 | |||
1 | 2 | 3 | |||
1 | 2 | 3 | |||
1 | 2.5 | 2.5 | |||
1 | 2 | 3 |
Excel formula:
=PAGE_TREND_TEST({1.5,3,1.5;1.5,1.5,3;1,3,2;1.5,3,1.5;1,2,3;1,2.5,2.5;1,2,3;1,2,3;1,2.5,2.5;1,2,3}, TRUE)
Expected output:
L_statistic | p_value | method |
---|---|---|
133.5 | 0.001819116195 | exact |
Example 4: Custom Predicted Ranks
Inputs:
data | ranked | predicted_ranks | method | ||
---|---|---|---|---|---|
4 | 3 | 3 | FALSE | 2,3,1 | |
2 | 4 | 2 | |||
3 | 5 | 3 | |||
3 | 2 | 1 | |||
3 | 2 | 2 | |||
4 | 5 | 2 | |||
2 | 4 | 1 | |||
4 | 4 | 3 | |||
4 | 5 | 2 | |||
3 | 4 | 1 |
Excel formula:
=PAGE_TREND_TEST({4,3,3;2,4,2;3,5,3;3,2,1;3,2,2;4,5,2;2,4,1;4,4,3;4,5,2;3,4,1}, FALSE, {2,3,1})
Expected output:
L_statistic | p_value | method |
---|---|---|
133.5 | 0.001819116195 | exact |
This demonstrates the use of custom predicted ranks for the treatments.
Python Code
from scipy.stats import page_trend_test as scipy_page_trend_test
def page_trend_test(data, ranked=False, predicted_ranks=None, method="auto"):
"""
Perform Page’s L trend test for monotonic trends across treatments.
Args:
data: 2D list of shape (m, n), each row is a subject, each column is a treatment.
ranked: If True, data is already ranked; otherwise, it will be ranked within each row (default: False).
predicted_ranks: 2D list (1 row) or None. Predicted ranks for each treatment (default: None, i.e., [1,2,...,n]).
method: Method for p-value calculation: "auto", "asymptotic", or "exact" (default: "auto").
Returns:
1-row 2D list: [L_statistic, p_value, method], or error message (str) if input is invalid.
This example function is provided as-is without any representation of accuracy.
"""
# Validate data
if not isinstance(data, list) or len(data) < 2 or not isinstance(data[0], list) or len(data[0]) < 3:
return "Invalid input: data must be a 2D list with at least 2 rows and 3 columns."
try:
arr = [[float(x) for x in row] for row in data]
except Exception:
return "Invalid input: data must contain only numeric values."
# Validate ranked
if isinstance(ranked, list):
if len(ranked) == 1 and isinstance(ranked[0], bool):
ranked = ranked[0]
elif len(ranked) == 1 and isinstance(ranked[0], str):
ranked = ranked[0].strip().lower() == "true"
else:
ranked = bool(ranked)
# Validate predicted_ranks
pr = None
if predicted_ranks is not None:
if isinstance(predicted_ranks, list):
if len(predicted_ranks) == 1 and isinstance(predicted_ranks[0], list):
pr = [float(x) for x in predicted_ranks[0]]
else:
pr = [float(x) for x in predicted_ranks]
else:
return "Invalid input: predicted_ranks must be a 2D or 1D list."
# Validate method
if method is None:
method = "auto"
if isinstance(method, list):
if len(method) == 1:
method = str(method[0])
else:
return "Invalid input: method must be a string."
try:
res = scipy_page_trend_test(arr, ranked=ranked, predicted_ranks=pr, method=method)
except Exception as e:
return f"scipy.page_trend_test error: {e}"
return [[float(res.statistic), float(res.pvalue), str(res.method)]]