# Ansari-Bradley test (PR#2252)

Torsten Hothorn Torsten.Hothorn@rzmail.uni-erlangen.de
Wed, 6 Nov 2002 08:55:16 +0100 (MET)

```
> Full_Name: Wei Xu
> Version: 1.5.1
> OS: WindowsME
> Submission from: (NULL) (63.215.238.92)
>
>
> The P-value for a two.sided test is not consistent with the confidence
> interval.
> For example, P-value=0.1372, but the 95% CI doesn't include the H0 value(1).
>
> > x
>   0.80 0.83 1.89 1.04 1.45 1.38 1.91 1.64 0.73 1.46
> > y
>  1.15 0.88 0.90 0.74 1.21
> > ansari.test(x,y,alternative="two.sided",conf.int=TRUE,conf.level=0.95)
>
>
> data:  x and y
> AB = 36, p-value = 0.1372
> alternative hypothesis: true ratio of scales is not equal to 1
> 95 percent confidence interval:
>  1.081081 2.581081
> sample estimates:
> ratio of scales
>        1.972973
>

First: sorry for the delay but I was not able to solve this until now.

Second: well, it is both a bug and a statistical problem,
`ansari.test' should know about (a version that does is
attached).

The truth is that x and y are assumed to be "appropriately centered" as
Bauer (1972) states (see the man page for the reference). The model is Y ~
G and X ~ F with

G(x) = F(x / s) (or the other way round ...)

without modelling the "shift". And your example reads

R> x <- c(0.80, 0.83, 1.89, 1.04, 1.45, 1.38, 1.91, 1.64, 0.73, 1.46)
R> y <- c(1.15, 0.88, 0.90, 0.74, 1.21)
R> summary(x)
Min. 1st Qu.  Median    Mean 3rd Qu.    Max.
0.7300  0.8825  1.4150  1.3130  1.5950  1.9100
R> summary(y)
Min. 1st Qu.  Median    Mean 3rd Qu.    Max.
0.740   0.880   0.900   0.976   1.150   1.210

so x seems to be larger on average. I think this corresponds to the
Behrens-Fisher problem in some way but I'm not aware of any literature...
The confidence set cannot be computed by inverting the test for your
(raw) data but currently `ansari.test' forces the computation be using
the extreme values of the possible ratios (which should at least give a
warning).

Now (with ansari.test as attached)

R> print(ansari.test(x-mean(x),y-mean(y), conf.int=TRUE))

data:  x - mean(x) and y - mean(y)
AB = 37, p-value = 0.2171
alternative hypothesis: true ratio of scales is not equal to 1
95 percent confidence interval:
0.6282051 6.0729167
sample estimates:
ratio of scales
2.468075

is consistent (using the median can cause problems with ties). Using the
mean seems to be ok (I just simulated some situations, I can give you
details if you like).

best,

Torsten

*************************************************************************

ansari.test <- function(x, ...) UseMethod("ansari.test")

# altered with respect to bug report 2252
# and some additional improvements

ansari.test.default <-
function(x, y, alternative = c("two.sided", "less", "greater"),
exact = NULL, conf.int = FALSE, conf.level = 0.95, ...)
{
alternative <- match.arg(alternative)
if(conf.int) {
if(!((length(conf.level) == 1)
&& is.finite(conf.level)
&& (conf.level > 0)
&& (conf.level < 1)))
stop("conf.level must be a single number between 0 and 1")
}
DNAME <- paste(deparse(substitute(x)), "and", deparse(substitute(y)))

x <- x[complete.cases(x)]
y <- y[complete.cases(y)]
m <- length(x)
if(m < 1)
stop("not enough x observations")
n <- length(y)
if(n < 1)
stop("not enough y observations")
N <- m + n

r <- rank(c(x, y))
STATISTIC <- sum(pmin(r, N - r + 1)[seq(along = x)])
TIES <- (length(r) != length(unique(r)))

if(is.null(exact))
exact <- ((m < 50) && (n < 50))

if(exact && !TIES) {
pansari <- function(q, m, n) {
.C("pansari",
as.integer(length(q)),
p = as.double(q),
as.integer(m),
as.integer(n),
PACKAGE = "ctest")\$p
}
PVAL <-
switch(alternative,
two.sided = {
if (STATISTIC > ((m + 1)^2 %/% 4
+ ((m * n) %/% 2) / 2))
p <- 1 - pansari(STATISTIC - 1, m, n)
else
p <- pansari(STATISTIC, m, n)
min(2 * p, 1)
},
less = 1 - pansari(STATISTIC - 1, m, n),
greater = pansari(STATISTIC, m, n))
if (conf.int) {
qansari <- function(p, m, n) {
.C("qansari",
as.integer(length(p)),
q = as.double(p),
as.integer(m),
as.integer(n),
PACKAGE = "ctest")\$q
}
alpha <- 1 - conf.level
x <- sort(x)
y <- sort(y)
ab <- function(sig) {
rab <- rank(c(x/sig, y))
sum(pmin(rab, N - rab + 1)[seq(along = x)])
}
ratio <- outer(x,y,"/")
aratio <- ratio[ratio >= 0]
sigma <- sort(aratio)

cci <- function(alpha) {
u <- absigma - qansari(alpha/2,  m, n)
l <- absigma - qansari(1 - alpha/2, m, n)
# check if the statistic exceeds both quantiles first
uci <- NULL
lci <- NULL
if(length(u[u >= 0]) == 0) {
uci <- sigma
warning("samples differ in location: confidence set maybe wrong")
}
if (length(l[l > 0]) == 0) {
lci <- sigma[length(sigma)]
warning("samples differ in location: confidence set maybe wrong")
}
if (is.null(uci)) {
u[u < 0] <- NA
uci <- min(sigma[which(u == min(u, na.rm=TRUE))])
}
if (is.null(lci)) {
l[l <= 0] <- NA
lci <- max(sigma[which(l == min(l, na.rm=TRUE))])
}
# the process of the statistics does not need to be monotone
# in sigma: check this and interchange quantiles.
if (uci > lci) {
l <- absigma - qansari(alpha/2,  m, n)
u <- absigma - qansari(1 - alpha/2, m, n)
u[u < 0] <- NA
uci <- min(sigma[which(u == min(u, na.rm=TRUE))])
l[l <= 0] <- NA
lci <- max(sigma[which(l == min(l, na.rm=TRUE))])
}
c(uci, lci)
}

cint <- if(length(sigma) < 1) {
warning("Cannot compute confidence interval")
c(NA, NA)
}
else {
# compute statistics directly: computing the steps is not
# faster
absigma <- sapply(sigma + c(diff(sigma)/2, sigma[length(sigma)]*1.01), ab)
switch(alternative, two.sided = {
cci(alpha)
}, greater= {
c(cci(alpha*2), Inf)
}, less= {
c(0, cci(alpha*2))
})
}
attr(cint, "conf.level") <- conf.level
u <- absigma - qansari(0.5, m, n)
sgr <- sigma[u <= 0]
if (length(sgr) == 0) sgr <- NA
else sgr <- max(sgr)
sle <- sigma[u > 0]
if (length(sle) == 0) sle <- NA
else sle <- min(sle)
ESTIMATE <- mean(c(sle, sgr))
}
}
else {
EVEN <- ((N %% 2) == 0)
normalize <- function(s, r, TIES, m=length(x), n=length(y)) {
z <- if(EVEN)
s - m * (N + 2)/4
else
s - m * (N + 1)^2/(4 * N)
if (!TIES) {
SIGMA <- if(EVEN)
sqrt((m * n * (N + 2) * (N - 2))/(48 * (N - 1)))
else
sqrt((m * n * (N + 1) * (3 + N^2))/(48 * N^2))
}
else {
r <- rle(sort(pmin(r, N - r + 1)))
SIGMA <- if(EVEN)
sqrt(m * n
* (16 * sum(r\$l * r\$v^2) - N * (N + 2)^2)
/ (16 * N * (N - 1)))
else
sqrt(m * n
* (16 * N * sum(r\$l * r\$v^2) - (N + 1)^4)
/ (16 * N^2 * (N - 1)))
}
z / SIGMA
}
p <- pnorm(normalize(STATISTIC, r, TIES))
PVAL <- switch(alternative,
two.sided = 2 * min(p, 1 - p),
less = 1 - p,
greater = p)

if(conf.int && !exact) {
alpha <- 1 - conf.level
ab <- function(sig, zq) {
r <- rank(c(x / sig, y))
s <- sum(pmin(r, N -r + 1)[seq(along = x)])
TIES <- (length(r) != length(unique(r)))
normalize(s, r, TIES, length(x), length(y)) - zq
}
## use uniroot here
## compute the range of sigma first
srangepos <- NULL
srangeneg <- NULL
if (any(x[x > 0]) && any(y[y > 0]))
srangepos <- c(min(x[x>0], na.rm=TRUE)/max(y[y>0], na.rm=TRUE),
max(x[x>0], na.rm=TRUE)/min(y[y>0], na.rm=TRUE))
if (any(x[x <= 0]) && any(y[y < 0]))
srangeneg <- c(min(x[x<=0], na.rm=TRUE)/max(y[y<0], na.rm=TRUE),
max(x[x<=0], na.rm=TRUE)/min(y[y<0], na.rm=TRUE))
if (any(is.infinite(c(srangepos, srangeneg)))) {
warning("cannot compute asymptotic confidence intervals or estimator")
conf.int <- FALSE
} else {
ccia <- function(alpha) {
# check if the statistic exceeds both quantiles first
statu <- ab(srange, zq=qnorm(alpha/2))
statl <- ab(srange, zq=qnorm(alpha/2, lower=FALSE))
if (statu > 0) {
u <- srange
warning("samples differ in location: confidence set maybe wrong")
} else
u <- uniroot(ab, srange, tol=1e-4, zq=qnorm(alpha/2))\$root
if (statl < 0) {
l <- srange
warning("samples differ in location: confidence set maybe wrong")
} else
l <- uniroot(ab, srange, tol=1e-4, zq=qnorm(alpha/2, lower=FALSE))\$root
# the process of the statistics does not need to be
# monotone: sort is ok here
sort(c(u, l))
}
srange <- range(c(srangepos, srangeneg), na.rm=FALSE)
cint <- switch(alternative, two.sided = {
ccia(alpha)
}, greater= {
c(ccia(alpha*2), Inf)
}, less= {
c(0, ccia(alpha*2))
})
attr(cint, "conf.level") <- conf.level
# check if the statistic exceeds both quantiles first
statu <- ab(srange, zq=0)
statl <- ab(srange, zq=0)
if (statu > 0 || statl < 0) {
ESTIMATE <- NA
warning("cannot compute estimate")
} else
ESTIMATE <- uniroot(ab, srange, tol=1e-4, zq=0)\$root
}
}
if(exact && TIES) {
warning("Cannot compute exact p-value with ties")
if(conf.int)
warning(paste("Cannot compute exact confidence",
"intervals with ties"))
}
}

names(STATISTIC) <- "AB"
RVAL <- list(statistic = STATISTIC,
p.value = PVAL,
null.value = c("ratio of scales" = 1),
alternative = alternative,
method = "Ansari-Bradley test",
data.name = DNAME)
if(conf.int)
RVAL <- c(RVAL,
list(conf.int = cint,
estimate = c("ratio of scales" = ESTIMATE)))
class(RVAL) <- "htest"
return(RVAL)
}

ansari.test.formula <-
function(formula, data, subset, na.action, ...)
{
if(missing(formula)
|| (length(formula) != 3)
|| (length(attr(terms(formula[-2]), "term.labels")) != 1)
|| (length(attr(terms(formula[-3]), "term.labels")) != 1))
stop("formula missing or incorrect")
if(missing(na.action))
na.action <- getOption("na.action")
m <- match.call(expand.dots = FALSE)
if(is.matrix(eval(m\$data, parent.frame())))
m\$data <- as.data.frame(data)
m[] <- as.name("model.frame")
m\$... <- NULL
mf <- eval(m, parent.frame())
DNAME <- paste(names(mf), collapse = " by ")
names(mf) <- NULL
response <- attr(attr(mf, "terms"), "response")
g <- factor(mf[[-response]])
if(nlevels(g) != 2)
stop("grouping factor must have exactly 2 levels")
DATA <- split(mf[[response]], g)
names(DATA) <- c("x", "y")
y <- do.call("ansari.test", c(DATA, list(...)))
y\$data.name <- DNAME
y
}

-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-
r-devel mailing list -- Read http://www.ci.tuwien.ac.at/~hornik/R/R-FAQ.html
Send "info", "help", or "[un]subscribe"
(in the "body", not the subject !)  To: r-devel-request@stat.math.ethz.ch
_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._

```