How to Detect Trends with the Mann‑Kendall Test in Python
This article explains how to determine whether a time‑series dataset exhibits a monotonic trend using the non‑parametric Mann‑Kendall test, walks through its statistical foundations, shows the calculation steps with sample sales data, and provides a complete Python implementation for practical analysis.
Determining Monotonicity of Data
We have monthly sales data for a year and want to know if the series is monotonic. A quick visual check shows an increase then decrease, so it is not strictly monotonic. To quantify the trend despite possible measurement error, we use the Mann‑Kendall test.
Mann‑Kendall Test
The Mann‑Kendall test (M‑K test) is a non‑parametric hypothesis test for detecting a monotonic trend (increasing, decreasing, or none) in a time series. It compares each data point with all previous points, counting how many are smaller or larger, and uses the difference to assess trend.
The null hypothesis states that the series is independent and identically distributed; the alternative hypothesis asserts a monotonic trend. If the p‑value is below a chosen significance level (commonly 0.05), the null hypothesis is rejected, indicating a trend.
Advantages: no distributional assumptions, applicable to various time‑series types, including non‑normal data. Limitations: cannot identify the specific form of the trend and is insensitive to periodic variations.
Computation Steps
Using the example sales data, we compute the Mann‑Kendall statistic S and its variance, then standardize to obtain Z. The formulas involve the sign function and consider ties. The standardized Z is compared against the normal distribution to derive the p‑value.
For the given data, the calculated Z and p‑value indicate no significant trend.
Python Implementation
The following Python code implements the Mann‑Kendall test:
<code>import numpy as np
from scipy.stats import norm
alpha = 0.05 # significance level
def mann_kendall_test(x):
"""Mann‑Kendall trend test for a given data sequence x.
Args:
x: A list or numpy array of data sequence.
Returns:
trend: The calculated trend ('increasing', 'decreasing', or 'no trend').
p_value: The p‑value of the test.
"""
n = len(x)
s = 0
for i in range(n - 1):
for j in range(i + 1, n):
s += np.sign(x[j] - x[i])
# Calculate the variance of the test statistic.
var_s = (n * (n - 1) * (2 * n + 5)) / 18
# Calculate the standardized test statistic.
if s > 0:
z = (s - 1) / np.sqrt(var_s)
elif s < 0:
z = (s + 1) / np.sqrt(var_s)
else:
z = 0
# Calculate the p‑value of the test.
p_value = 2 * (1 - norm.cdf(abs(z)))
# Determine the trend based on the sign of the test statistic.
if p_value < alpha:
if z > 0:
trend = 'increasing'
elif z < 0:
trend = 'decreasing'
else:
trend = 'no trend'
else:
trend = 'no trend'
return trend, p_value
</code>After defining the function, we apply it to the sales data:
<code>mann_kendall_test(Sales)
</code>The result is ('no trend', 0.49288623517292063). The p‑value is not significant, so we conclude that the series does not exhibit a clear trend.
References:
Jianshu article on Mann‑Kendall trend test algorithm.
Wei Yu, *Non‑Parametric Statistical Methods* (4th ed.), Higher Education Press, 2009.
Model Perspective
Insights, knowledge, and enjoyment from a mathematical modeling researcher and educator. Hosted by Haihua Wang, a modeling instructor and author of "Clever Use of Chat for Mathematical Modeling", "Modeling: The Mathematics of Thinking", "Mathematical Modeling Practice: A Hands‑On Guide to Competitions", and co‑author of "Mathematical Modeling: Teaching Design and Cases".
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.