Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
For a numeric series already arranged in time order, the quickest way to run a Cox–Stuart test in R is with randtests:
install.packages("randtests")
library(randtests)
result <- cox.stuart.test(x)
result
The default is a two-sided test for an upward or downward trend. The test compares signs of paired changes; it does not estimate how steep a trend is. Make sure x is in chronological order before testing.
What the Cox–Stuart test tells you
The Cox–Stuart test is a nonparametric, sign-based test for a trend in an ordered numeric series. Its null hypothesis is that paired changes are equally likely to be positive or negative. A two-sided alternative asks whether a directional trend exists; one-sided alternatives ask specifically whether later values tend to be larger or smaller.
Free tools Windows power users keep installed
One-click scans. No signup required.
For the conventional half-series pairing, observations from the beginning are compared with corresponding observations from the end. The test counts positive and negative differences, omitting zero differences from the sign-test calculation. Under the null, positive signs follow a binomial distribution with probability 0.5. This tests direction, not the size of change. NIST describes the test as a sign test for trend.
#1 Best Overall
Prepare and run the test in R
Keep the observations in their real sequence
If the series is stored in a data frame, sort by its time variable before extracting the response. Otherwise, the test will analyze the supplied order, even if that order is wrong.
dat <- dat[order(dat$time), ]
x <- dat$value
install.packages("randtests")
library(randtests)
result <- cox.stuart.test(x)
result
The randtests function accepts a numeric vector and supports "two.sided", "left.sided", and "right.sided" alternatives. Its documentation describes removing missing values, pairing the first and second portions of the series, dropping ties, and returning an htest result. See the cox.stuart.test() reference; in R, ?cox.stuart.test opens the installed help page.
Choose the direction deliberately
Use a two-sided test when the direction was not specified in advance. In randtests, the one-sided labels are counterintuitive: its documentation maps "left.sided" to an upward trend and "right.sided" to a downward trend.
cox.stuart.test(x, alternative = "two.sided") # either direction
cox.stuart.test(x, alternative = "left.sided") # upward
cox.stuart.test(x, alternative = "right.sided")# downward
Choose a one-sided alternative only when that direction is part of the question before looking at the results. The labels are specific to this function; other packages use different names.
Understand the paired changes
For an even-length vector, the first half is paired with the second half. For an odd-length vector, the midpoint is left out. With 19 observations, for example, the construction compares x[1] with x[11] through x[9] with x[19]; x[10] is unused. This is the half-series construction documented by randtests and NIST.
Inspecting the differences makes the direction and ties visible:
Rank #3
x <- x[!is.na(x)]
n <- length(x)
c <- if (n %% 2 == 0) n / 2 else (n + 1) / 2
early <- x[1:(n - c)]
late <- x[(c + 1):n]
d <- late - early
d
table(sign(d))
Each positive value in d is a later observation larger than its paired earlier observation; each negative value points downward. A zero is a tie and contributes no sign to the test. The paired differences can be passed directly to a binomial sign test:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
d_no_ties <- d[d != 0]
S <- sum(d_no_ties > 0)
m <- length(d_no_ties)
binom.test(S, m, p = 0.5, alternative = "two.sided")
The examples above assume at least two non-missing observations. For production code, also check that the vector has enough observations to form pairs.
Reproduce the calculation with base R
This function makes the direction convention explicit: "greater" means more positive later-minus-earlier differences, and "less" means more negative ones. It also returns the pair counts and differences so the p-value is not the only reported result.
Rank #4
cox_stuart_base <- function(x,
alternative = c("two.sided", "greater", "less")) {
alternative <- match.arg(alternative)
if (!is.numeric(x)) {
stop("x must be a numeric vector.")
}
x <- x[!is.na(x)]
if (length(x) < 2L) {
stop("x must contain at least two non-missing observations.")
}
n <- length(x)
c <- if (n %% 2L == 0L) n / 2L else (n + 1L) / 2L
m_pairs <- n - c
if (m_pairs < 1L) {
stop("Not enough observations to form a pair.")
}
early <- x[seq_len(m_pairs)]
late <- x[(c + 1L):n]
differences <- late - early
ties <- sum(differences == 0)
signs <- differences[differences != 0]
positive <- sum(signs > 0)
negative <- sum(signs < 0)
if (length(signs) == 0L) {
return(list(
method = "Cox-Stuart sign test",
statistic = NA_real_,
p.value = 1,
alternative = alternative,
pairs = length(differences),
usable_pairs = 0L,
positive = positive,
negative = negative,
ties = ties,
differences = differences
))
}
p_value <- binom.test(
x = positive,
n = length(signs),
p = 0.5,
alternative = alternative
)$p.value
list(
method = "Cox-Stuart sign test",
statistic = positive,
p.value = p_value,
alternative = alternative,
pairs = length(differences),
usable_pairs = length(signs),
positive = positive,
negative = negative,
ties = ties,
differences = differences
)
}
Example calls:
x <- c(10, 11, 9, 12, 13, 14, 15, 16, 17, 18)
cox_stuart_base(x, alternative = "two.sided")
cox_stuart_base(x, alternative = "greater")
cox_stuart_base(x, alternative = "less")
Interpret the output without overstating it
The p-value measures how unusual the observed split of positive and negative signs would be under the 50:50 null, for the selected alternative. A small p-value is evidence against that null in the tested direction; it does not prove a trend or show that the change is practically important. A p-value above the chosen threshold means the test did not reject the null, not that the series has no trend.
Report the number of observations, paired differences, positive and negative signs, ties, alternative, and p-value. A useful summary also includes a plot and, when magnitude matters, a slope estimate. Cox–Stuart itself supplies no slope or confidence interval for trend magnitude.
Account for missing data, ties, and dependence
Missing observations
randtests removes missing values, but deletion can change which observations are paired and compress gaps in time. If measurements are irregular or missingness matters, retain the time variable and state how gaps were handled; deleting NA values is not imputation.
sum(is.na(x))
ok <- complete.cases(dat$time, dat$value)
x <- dat$value[ok]
time <- dat$time[ok]
Ties reduce the usable evidence
Each tied pair is omitted from the sign count. Report ties and usable pairs, particularly when values are rounded or discrete: many ties leave fewer signs and can reduce power.
Check the assumptions behind the p-value
Nonparametric does not mean assumption-free. The sequence must be meaningfully ordered, pairing must suit the question, and the sign-test null must be appropriate. Strong serial dependence can undermine the nominal p-value because the paired signs may not behave like independent Bernoulli outcomes. For autocorrelated series, consider methods that model or account for dependence, such as regression with correlated errors, justified prewhitening, block bootstrap methods, or a serial-correlation-aware Mann–Kendall approach.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Package implementations are not identical
Check the documented method when comparing results across R packages. In particular, trend::cs.test() documents comparing the first third of a series with the last third, unlike the half-series pairing used by randtests and NIST.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errors| Implementation | Pairing or calculation | How to run |
|---|---|---|
randtests::cox.stuart.test() |
First and second portions; omits the midpoint for an odd-length series, and excludes tied differences from the sign count. | cox.stuart.test(x, alternative = "two.sided") |
trend::cs.test() |
Documentation describes first-third versus last-third comparison; for n ≤ 30 it describes a continuity correction, and for n > 30 a normal approximation. | cs.test(x) |
ANSM5::cox.stuart() |
Offers exact and asymptotic options, a continuity-correction control, and directional alternatives. | cox.stuart(x, alternative = "two.sided", cont.corr = TRUE, do.exact = TRUE, do.asymp = FALSE) |
References: randtests documentation, trend::cs.test() documentation, and ANSM5::cox.stuart() documentation. Do not assume their p-values are interchangeable: pairing and calculation options can differ.
Quick Recap
Choose another method when the question is different
- You need trend magnitude: Sen’s slope estimates a typical rate of change, while a trend test assesses evidence against a no-trend null. The
trendpackage documents Mann–Kendall and Sen’s slope procedures: CRAN package page. - You want a rank association between time and response: Spearman correlation is another option, but it uses a different statistic and is not equivalent to Cox–Stuart. For example:
cor.test(seq_along(x), x, method = "spearman", exact = FALSE). - You need a slope, confidence interval, covariates, or seasonal terms: Regression can address those questions if its model assumptions are defensible. A simple starting point is
fit <- lm(x ~ seq_along(x)); summary(fit); confint(fit); assess nonlinearity, outliers, heteroskedasticity, and autocorrelation. - The series is seasonal: Inspect seasonal plots and consider seasonal Mann–Kendall or a model with seasonal indicators instead of treating a repeating cycle as an unadjusted trend.
- The pattern is curved or has a sudden shift: A directional sign test may miss a U-shape or confuse a level change with a gradual trend. Consider spline or segmented regression, a change-point test, or a time-series model. The
trendpackage lists change-point procedures including Pettitt and Buishand tests in its package overview.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

