Sven Schreiber and Riccardo Jack Lucchetti
1.0
2017-06-08
Mann-Kendall nonparametric trend test
C22 C12
Performs the Mann-Kendall test for a trend in a time series,
apparently going back to:
Mann, H.B. (1945), Nonparametric tests against trend,
Econometrica, 13, 245-259;
and:
Kendall, M.G. (1970), Rank Correlation Methods, 2nd Ed.,
New York: Hafner.
Parameters:
x: series to examine. It should be given in (probably log) level form.
verbosity: (int) Can be set to zero to skip the printout. Default 1
(print results).
Returns a bundle with scalar elements:
test: the test statistic
pval: the corresponding (two-sided) p-value
tau: the Kendall measure
S: (expert/internal) the numerator of tau
s2: (expert/internal) the variance of S
Changelog:
June 2017: Version 1.0, initial release
```
/* Performs the Mann-Kendall test for a trend in a time series.
Returns a bundle with "test", "pval", "tau" (all scalars).
(and also for expert use "S" and "s2")
Set verbosity to 0 to mute the output.
*/
smpl x --contiguous
if sum(missing(x))
funcerr "Found missings. Aborting."
endif
matrix stats = SZs2(x)
scalar S = stats[1]
scalar Z = stats[2]
scalar s2 = stats[3]
scalar tau = stats[4]
pv = 2 * (1 - cnorm(abs(Z))) # two-sided
if verbosity
print "Mann-Kendall test"
print "H0: no trend"
print "H1: monotonic trend"
print "--------"
printf "tau = %g; Test statistic Z: %f\n", tau, Z
printf "p-value (two-sided): %f\n", pv
endif
bundle b
scalar b.test = Z
scalar b.pval = pv
scalar b.S = S
scalar b.tau = tau
# additional / debug:
scalar b.s2 = s2
return b
```

```
# computes S
matrix mx = {x}
matrix m = vech(mx .- mx')
m = m ? ( m .> 0 ? 1 : -1 ) : 0
scalar S = -sumc(m)
# check for ties
scalar ties = min(abs(diff(sort(x)))) < 1.0e-12 # do we have ties?
if ties
matrix f = aggregate(x, x)[,2]
# obsolete:
# scalar p = sumc(m .> 1) # number of values with >1 occurrence
endif
# computes the variance s2
# = (1/18)* ( n(n-1)(2n+5) - \sum_1^p t_j(t_j -1)(2t_j + 5))
n = $t2 - ($t1 - 1)
s2 = n * (n-1) * (2*n + 5) # only the beginning...
if ties
matrix mm = f .* (f - 1)
s2 -= sumc( mm .* (2*f + 5) )
endif
s2 /= 18
# compute the transformation Z
scalar Z = S ? ( S > 0 ? S-1 : S+1 ) : 0
Z /= sqrt(s2)
# compute D
scalar D1 = n * (n-1) / 2
scalar D0 = D1
if ties
D0 -= 0.5 * sumc(mm)
endif
D = sqrt(D0 * D1)
return {S, Z, s2, S/D}
```

include MannKendall.gfn
# artificial data
nulldata 256
set seed 23
setobs 1 1 --special-time-series
x = floor(filter(0.1+normal(),1,0.95))
bundle a = MannKendall(x)
# show some internals
eval a.S
eval a.s2
## another example
open bjg
series r = ldiff(g)
# de-activate the first missing due to difference
smpl +1 ;
# don't grab the results, just see the printout
MannKendall(r)
# now an artificial series with ties
r = floor(filter(normal()+0.1,1,0.9))
# with printout
a = MannKendall(r)
# without printout:
a = MannKendall(r, 0)
eval a.test ~ a.pval