There is a Mann-Kendall Evaluation that can be done in ProUCL. Is there something equivalent (or close to equivalent) in JMP? I'd like to run an existing function/platform in JMP (no scripts).
Hi @FaceBiasBee678,
The Analyze > Multivariate platform has a Kendall's τ option that might be what you're looking for. I'm not familiar with ProUCL, so I might be answering completely incorrectly.
When you mention looking for something equivalent or close to equivalent, can you clarify what exactly you're looking for? For example, do you need a non-parametric test for correlation between variables (Kendall's τ might be what you're looking for), or are you just looking to see if there's correlation between 2 variables (Fit Y by X > Fit Line might better suit your needs)?
@Jed_Campbell : The Mann-Kendall test is a test used on time series data to determine if within a sequence of points there exists a trend up or down...Kendall Tau is not what this poster is looking for. Maybe there is some type of test for this in Time Series platform?
Apparently "searching the JMP User Community for the "Mann-Kendall Trend Test Add-In" will allow you to download a free script that generates the exact regulatory tables automatically." Has anyone done this and can provide the script along with some pointers?
A quick bit of "Claude"-ing comes up with this:
// ===================================================================== // Mann-Kendall Trend Test + Sen's Slope (JSL) // --------------------------------------------------------------------- // Code created by Claude (Anthropic). // Prompt summary: User asked for a JSL script that performs the // Mann-Kendall test for monotonic trend in a time series (S statistic, // tie-corrected variance, Z, p-value, Kendall's tau) plus Sen's slope // with a confidence interval. //// // Usage: open a data table, run this script, pick the response column // (required), an optional time/order column, and alpha. // ===================================================================== Names Default To Here( 1 ); // --------------------------------------------------------------------- // Helper: Sign( v ) returns +1 if v > 0, -1 if v < 0, and 0 if v == 0 // --------------------------------------------------------------------- Sign = Function( {v}, If( v > 0, 1, v < 0, -1, 0 ) ); // --------------------------------------------------------------------- // STEP 1: Select data table and columns // --------------------------------------------------------------------- dt = Current Data Table(); If( Is Empty( dt ), Throw( "Open a data table before running this script." ) ); dlg = Column Dialog( yCol = ColList( "Y, Response", Max Col( 1 ), Min Col( 1 ), Data Type( Numeric ) ), xCol = ColList( "Time / Order (optional; row order used if blank)", Max Col( 1 ) ), HList( "Alpha", alphaBox = EditNumber( 0.05 ) ) ); If( dlg["Button"] == -1, Throw( "Cancelled." ) ); yCol = dlg["yCol"]; xCol = dlg["xCol"]; alpha = dlg["alphaBox"]; yName = Column( dt, yCol[1] ) << Get Name; hasX = N Items( xCol ) > 0; If( hasX, xName = Column( dt, xCol[1] ) << Get Name, xName = "Observation Order" ); // --------------------------------------------------------------------- // STEP 2: Pull values, drop missing, and sort by time/order // --------------------------------------------------------------------- yAll = Column( dt, yName ) << Get Values; nAll = N Rows( yAll ); If( hasX, xAll = Column( dt, xName ) << Get Values, xAll = 1 :: nAll // row order as time index ); keep = {}; For( i = 1, i <= nAll, i++, If( !Is Missing( yAll[i] ) & !Is Missing( xAll[i] ), Insert Into( keep, i ) ) ); n = N Items( keep ); If( n < 4, Throw( "Need at least 4 non-missing observations." ) ); y = J( n, 1, . ); x = J( n, 1, . ); For( i = 1, i <= n, i++, y[i] = yAll[keep[i]]; x[i] = xAll[keep[i]]; ); ord = Rank( x ); // indices that sort x ascending y = y[ord]; x = x[ord]; // --------------------------------------------------------------------- // STEP 3: Mann-Kendall S statistic and Sen's pairwise slopes // --------------------------------------------------------------------- nPairs = n * (n - 1) / 2; slopes = J( nPairs, 1, . ); S = 0; k = 0; For( i = 1, i < n, i++, For( j = i + 1, j <= n, j++, S += Sign( y[j] - y[i] ); // +1 up, -1 down, 0 tie If( x[j] != x[i], // skip pairs with identical time stamps k++; slopes[k] = (y[j] - y[i]) / (x[j] - x[i]); ); ) ); slopes = slopes[1 :: k]; // trim unused preallocated slots nSlopes = k; // --------------------------------------------------------------------- // STEP 4: Tie-corrected variance of S // --------------------------------------------------------------------- ySorted = Sort Ascending( y ); tieTerm = 0; runLen = 1; For( i = 2, i <= n + 1, i++, If( i <= n & ySorted[i] == ySorted[i - 1], runLen += 1, // still inside a tied group If( runLen > 1, tieTerm += runLen * (runLen - 1) * (2 * runLen + 5) ); runLen = 1; ) ); varS = (n * (n - 1) * (2 * n + 5) - tieTerm) / 18; // --------------------------------------------------------------------- // STEP 5: Z statistic (continuity corrected), p-value, Kendall's tau // --------------------------------------------------------------------- If( S > 0, Z = (S - 1) / Sqrt( varS ), S < 0, Z = (S + 1) / Sqrt( varS ), Z = 0 ); pValue = 2 * (1 - Normal Distribution( Abs( Z ) )); tau = S / nPairs; // simple tau (not tau-b); equals tau-b when no ties zCrit = Normal Quantile( 1 - alpha / 2 ); If( pValue < alpha, If( Z > 0, trendText = "Significant INCREASING trend", trendText = "Significant DECREASING trend" ), trendText = "No significant monotonic trend" ); // --------------------------------------------------------------------- // STEP 6: Sen's slope, intercept, and confidence interval // CI follows the Gilbert (1987) rank-based approach (normal approx). // --------------------------------------------------------------------- sortedSlopes = Sort Ascending( slopes ); senSlope = Median( slopes ); senIntercept = Median( y - senSlope * x ); cAlpha = zCrit * Sqrt( varS ); m1 = (nSlopes - cAlpha) / 2; m2 = (nSlopes + cAlpha) / 2; loIdx = Max( 1, Min( nSlopes, Round( m1 ) ) ); hiIdx = Max( 1, Min( nSlopes, Round( m2 + 1 ) ) ); senLower = sortedSlopes[loIdx]; senUpper = sortedSlopes[hiIdx]; // --------------------------------------------------------------------- // STEP 7: Assemble labels/values for the test-statistic table + log // --------------------------------------------------------------------- ciPct = Round( 100 * (1 - alpha), 1 ); statLabels = {"Response", "Time / order variable", "n (non-missing)", "S", "Var(S) (tie-corrected)", "Z (continuity corrected)", "p-value (two-sided)", "Kendall tau (S / n(n-1)/2)", "Alpha", "Sen's slope (per unit time)", "Sen's slope lower " || Char( ciPct ) || "% CI", "Sen's slope upper " || Char( ciPct ) || "% CI", "Sen's intercept"}; statValues = {yName, xName, Char( n ), Char( S ), Format( varS, "Best", 8 ), Format( Z, "Fixed Dec", 4 ), Format( pValue, "Best", 6 ), Format( tau, "Fixed Dec", 4 ), Char( alpha ), Format( senSlope, "Best", 6 ), Format( senLower, "Best", 6 ), Format( senUpper, "Best", 6 ), Format( senIntercept, "Best", 6 )}; Write( "\!NMann-Kendall: ", yName, " vs ", xName, "\!N n = ", n, ", S = ", S, ", Z = ", Round( Z, 4 ), ", p = ", Round( pValue, 6 ), "\!N Sen's slope = ", senSlope, " (", ciPct, "% CI: ", senLower, " to ", senUpper, ")", "\!N ", trendText, "\!N" ); // --------------------------------------------------------------------- // STEP 8: Build (hidden) plot data table: time, observed value, Sen fit // Graph Builder needs a data table; it is closed with the report. // --------------------------------------------------------------------- dtPlot = New Table( "Mann-Kendall Plot Data: " || yName, Invisible, New Column( "Time", Numeric, Continuous, Set Values( x ) ), New Column( "Value", Numeric, Continuous, Set Values( y ) ), New Column( "Sen Fit", Numeric, Continuous, Set Values( senIntercept + senSlope * x ) ) ); // Color the conclusion by outcome (red = trend detected, green = none) concColor = If( pValue < alpha, "Red", "Green" ); // --------------------------------------------------------------------- // STEP 9: Build the custom output report window (Graph Builder + stats) // --------------------------------------------------------------------- win = New Window( "Mann-Kendall Trend Test: " || yName, V List Box( Text Box( "Mann-Kendall Trend Test with Sen's Slope", << Set Font Size( 14 ), << Set Font Style( "Bold" ) ), Text Box( "Response: " || yName || " | Time/Order: " || xName || " | n = " || Char( n ) ), Spacer Box( Size( 0, 8 ) ), // ----- Graph Builder: data points with Sen's slope line ----- Outline Box( "Trend Plot", dtPlot << Graph Builder( Size( 650, 400 ), Show Control Panel( 0 ), Variables( X( :Time ), Y( :Value ), Y( :Sen Fit, Position( 1 ) ) ), Elements( Points( X, Y( 1 ) ), Line( X, Y( 2 ) ) ) ) ), // ----- Test statistics table ----- Outline Box( "Test Statistics", Table Box( String Col Box( "Statistic", statLabels ), String Col Box( "Value", statValues ) ) ), // ----- Conclusion ----- Outline Box( "Conclusion", Text Box( trendText || " at alpha = " || Char( alpha ) || " (p = " || Format( pValue, "Best", 4 ) || ").", << Set Font Style( "Bold" ), << Font Color( concColor ) ), Text Box( "Sen's slope estimates the median change in " || yName || " per unit of " || xName || "." ) ), // ----- Notes ----- Outline Box( "Notes", Text Box( "H0: no monotonic trend. Z uses a continuity correction and the tie-corrected variance of S.\!N" || "Assumes independent observations; positive serial correlation inflates false positives.\!N" || "Normal approximation is weak for n < 10." ), << Close( 1 ) ), // ----- Optional export of statistics to a data table ----- Button Box( "Save Statistics to Data Table", New Table( "Mann-Kendall Results: " || yName, New Column( "Statistic", Character, Nominal, Set Values( statLabels ) ), New Column( "Value", Character, Nominal, Set Values( statValues ) ) ) ) ) ); // Close the hidden plot data table when the report window is closed win << On Close( Close( dtPlot, No Save ) );