﻿ Mann Kendall Trend Evaluation

# Mann Kendall Trend Evaluation

The Mann Kendall statistical method tests the statistical hypothesis that there is an upward or downward trend with a specified probability.  This is a non-parametric test, which means that it makes no presumptions about the underlying statistical model from which the data is drawn. The test is carried out by first sorting the data temporally and then comparing each of the sampled data points. An S score is calculated, which is essentially the net number of point-pairs indicating an upward trend. A positive S score indicates the possibility of an upward trend. A statistical test is applied to determine whether the S score is sufficiently large to indicate that the trend hypothesis is accepted for a preset level of probability.

The EnviroInsite code used in evaluating the Mann Kendall test is provided below so that users may carry out their own checks and have a reasonable certainty that the test is being carried out correctly.

// nPercentSig - percent significance

// nValue - number of values

// vals   - array of values to be tested sorted by the sample time

public string MannKendallEval(int PercentSig, int nValues, double[] vals )

{

//' Based on Data Quality Assessment: Statistical Methods for Practitioners, EPA QA/G-9S

//' www.epa.gov/quality/qs-docs/g9s-final.pdf

int S = CalcMannKendallS(nValues, vals );

string Hypothesis = "Inconclusive";

// nValues = 11

if (nValues > 10)

{

int[] tie_group = new int[nValues];

//' example data from page 109 of EPA QA/G-9S

//'vals(0) = 10.0

//'vals(1) = 10.0

//'vals(2) = 10.0

//'vals(3) = 5.0

//'vals(4) = 10.0

//'vals(5) = 20.0

//'vals(6) = 18.0

//'vals(7) = 17.0

//'vals(8) = 15.0

//'vals(9) = 24.0

//'vals(10) = 15.0

//' should result in nTies = 2

//' tie_group_sz(0) = 4

//' tie_group_sz(1) = 2

//' S =  22

//' var_s = 155.33

//' Z = 1.685

//int i = 0;

for (int k =0; k<nValues; k++)

tie_group[k] = 0;

int nTies = 0;

for (int k = 0; k<nValues -1; k++)

{

if (tie_group[k] == 0)

{

for(int j = k+1; j<nValues; j++)

{

if(vals[j] == vals[k])

{

if (tie_group[k] == 0)

{

nTies++;

tie_group[k] = nTies;

}

if ( tie_group[j] == 0)

tie_group[j] = nTies;

}

}

}

}

int[] tie_group_sz = new int[nTies];

for (int k = 0; k < nTies; k++ )

{

tie_group_sz[k] = 0;

for ( int j = 0; j < nValues; j++)

{

if(tie_group[j] == k + 1)

{

tie_group_sz[k]++;

}

}

}

double var_S = nValues * (nValues - 1.0) * (2.0 * nValues + 5.0) / 18.0;

for(int k = 0; k<nTies; k++)

var_S -= tie_group_sz[k] * (tie_group_sz[k] - 1) * (2 * tie_group_sz[k] + 5) / 18.0;

double Z = 0;

if( S > 0 )

Z = (S - 1.0) / Math.Sqrt(var_S);

else if ( S < 0 )

Z = (S + 1.0) / Math.Sqrt(var_S);

//' from Table A-1 of EPA QA/G-9S

if( PercentSig == 20 )

{

if (Z > 0.842 || Z < -0.842)

{

if (S > 0)

Hypothesis = "Positive Trend";

else

Hypothesis = "Negative Trend";

}

}

else if( PercentSig == 10 )

{

if(Z > 1.289 || Z< -1.289)

{

if (S > 0)

Hypothesis = "Positive Trend";

else

Hypothesis = "Negative Trend";

}

}

else if( PercentSig == 5 )

{

if(Z > 1.645 || Z< -1.645)

{

if (S > 0)

Hypothesis = "Positive Trend";

else

Hypothesis = "Negative Trend";

}

}

else if( PercentSig == 1 )

{

if(Z > 2.327 || Z< -2.327)

{

if (S > 0)

Hypothesis = "Positive Trend";

else

Hypothesis = "Negative Trend";

}

}

}

else

{

//' from Table A-1 of Guidance on Natural Attenuation for Petroleum Releases

//'  Remediation and Redevelopment Program, Wisconsin DNR

//' (difference from EPA table for 10 percent confidence interval due

//' to greater resolution in the Wisconsin table relative to that provided

//' in Table A-12a of EPA QA/G-9S

int[] S_cr_20 = {-1, -1, -1, -1, 4, 5, 6, 7, 8, 10, 11};

int[] S_cr_10 = {-1, -1, -1, -1, 6, 7, 8, 10, 11, 14, 16};

//' from Table A-12a of EPA QA/G-9S

//'Dim S_cr_10 As Integer() = New Integer() {-1, -1, -1, -1, 6, 8, 9, 11, 12, 14, 17}

int[] S_cr_05 = {-1, -1, -1, -1, 6, 8, 11, 13, 16, 18, 21};

int[] S_cr_01 = {-1, -1, -1, -1, -1, 10, 13, 17, 20, 24, 27};

if( PercentSig == 20 )

{

if (S_cr_20[nValues] < 0 )

Hypothesis = "Inconclusive";

else if ( S > 0 && S >= S_cr_20[nValues] )

Hypothesis = "Positive Trend";

else if ( S < 0 && S <= -S_cr_20[nValues] )

Hypothesis = "Negative Trend";

}

else if( PercentSig == 10 )

{

if (S_cr_10[nValues] < 0 )

Hypothesis = "Inconclusive";

else if ( S > 0 && S >= S_cr_10[nValues] )

Hypothesis = "Positive Trend";

else if ( S < 0 && S <= S_cr_10[nValues] )

Hypothesis = "Negative Trend";

}

else if( PercentSig == 5 )

{

if (S_cr_05[nValues] < 0 )

Hypothesis = "Inconclusive";

else if ( S > 0 && S >= S_cr_05[nValues] )

Hypothesis = "Positive Trend";

else if ( S < 0 && S <= -S_cr_05[nValues] )

Hypothesis = "Negative Trend";

}

else if(PercentSig == 1)

{

if (S_cr_01[nValues] < 0 )

Hypothesis = "Inconclusive";

else if ( S > 0 && S >= S_cr_01[nValues] )

Hypothesis = "Positive Trend";

else if ( S < 0 && S <= -S_cr_01[nValues] )

Hypothesis = "Negative Trend";

}

}

return Hypothesis;

}

int CalcMannKendallS(int nValues, double[] vals)

{

//' test data from pg. 109 of EPA QA/G-9S

//'    nValues = 11

//'      Dim vals(nValues) As Double

//'vals(1) = 10.0

//'vals(2) = 10.0

//'vals(3) = 5.0

//'vals(4) = 10.0

//'vals(5) = 20.0

//'vals(6) = 18.0

//'vals(7) = 17.0

//'vals(8) = 15.0

//'vals(9) = 24.0

//'vals(10) = 15.0

//' S = 22

int S = 0;

for (int k = 0; k < nValues - 1; k++)

{

for (int j = k + 1; j < nValues; j++)

{

if (vals[j] > vals[k])

S += 1;

else if (vals[j] < vals[k])

S -= 1;

}

}

return S;

}