blob: 0925dcc4fb0275c8f7cf5e0a02cf4bdc0a78193e [file] [log] [blame]
# File src/library/stats/R/poisson.tests.R
# Part of the R package, https://www.R-project.org
#
# Copyright (C) 1995-2012 The R Core Team
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# A copy of the GNU General Public License is available at
# https://www.R-project.org/Licenses/
poisson.test <- function(x, T = 1, r = 1, alternative =
c("two.sided", "less", "greater"),
conf.level = 0.95)
{
DNAME <- deparse(substitute(x))
DNAME <- paste(DNAME, "time base:", deparse(substitute(T)))
if ((l <- length(x)) != length(T))
if (length(T) == 1L)
T <- rep(T, l)
else
stop("'x' and 'T' have incompatible length")
xr <- round(x)
if(any(!is.finite(x) | (x < 0)) || max(abs(x-xr)) > 1e-7)
stop("'x' must be finite, nonnegative, and integer")
x <- xr
if(any(is.na(T) | (T < 0)))
stop("'T' must be nonnegative")
if ((k <- length(x)) < 1L)
stop("not enough data")
if (k > 2L)
stop("the case k > 2 is unimplemented")
if(!missing(r) && (length(r) > 1 || is.na(r) || r < 0 ))
stop ("'r' must be a single positive number")
alternative <- match.arg(alternative)
if (k == 2) {
RVAL <- binom.test(x, sum(x), r * T[1L]/(r * T[1L] + T[2L]),
alternative=alternative, conf.level=conf.level)
RVAL$data.name <- DNAME
RVAL$statistic <- c(count1 = x[1L])
RVAL$parameter <- c("expected count1" = sum(x) * r * T[1L]/sum(T * c(1, r)))
RVAL$estimate <- c("rate ratio" = (x[1L]/T[1L])/(x[2L]/T[2L]))
pp <- RVAL$conf.int
RVAL$conf.int <- pp/(1 - pp)*T[2L]/T[1L]
names(r) <- "rate ratio"
RVAL$null.value <- r
RVAL$method <- "Comparison of Poisson rates"
return (RVAL)
} else {
m <- r * T
PVAL <- switch(alternative,
less = ppois(x, m),
greater = ppois(x - 1, m, lower.tail = FALSE),
two.sided = {
if(m == 0)
(x == 0)
else {
## Do
## d <- dpois(0 : inf, r * T)
## sum(d[d <= dpois(x, r * T)])
## a bit more efficiently ...
## Note that we need a little fuzz.
relErr <- 1 + 1e-7
d <- dpois(x, r * T)
## This is tricky: need to be sure
## only to sum values in opposite tail
## and not count x twice.
## For the Poisson dist., the mode will
## equal the mean if it is an integer.
if (x == m)
1
else if (x < m) {
## Slightly trickier than in the binomial
## because we cannot use infinite-length i
N <- ceiling(2 * m - x)
while (dpois(N, m) > d)
N <- 2 * N
i <- seq.int(from = ceiling(m), to = N)
y <- sum(dpois(i, m) <= d * relErr)
ppois(x, m) +
ppois(N - y, m, lower.tail = FALSE)
} else {
i <- seq.int(from = 0, to = floor(m))
y <- sum(dpois(i, m) <= d * relErr)
ppois(y - 1, m) +
ppois(x - 1, m, lower.tail = FALSE)
}
}
})
## Determine m s.t. Prob(Pois(m) >= x) = alpha.
## Use that for x > 0,
## Prob(Pois >= x) = pgamma(m, x).
p.L <- function(x, alpha) {
if(x == 0) # No solution
0
else
qgamma(alpha, x)
}
## Determine p s.t. Prob(B(n,p) <= x) = alpha.
## Use that for x < n,
## Prob(Pois(m) <= x) = 1 - pgamma(m, x + 1).
p.U <- function(x, alpha)
qgamma(1 - alpha, x + 1)
CINT <- switch(alternative,
less = c(0, p.U(x, 1 - conf.level)),
greater = c(p.L(x, 1 - conf.level), Inf),
two.sided = {
alpha <- (1 - conf.level) / 2
c(p.L(x, alpha), p.U(x, alpha))
}) / T
attr(CINT, "conf.level") <- conf.level
ESTIMATE <- x / T
names(x) <- "number of events" # or simply "x" ??
names(T) <- "time base" # or simply "n" ??
names(ESTIMATE) <-
names(r) <- "event rate" # or simply "p" ??
structure(list(statistic = x,
parameter = T,
p.value = PVAL,
conf.int = CINT,
estimate = ESTIMATE,
null.value = r,
alternative = alternative,
method = "Exact Poisson test",
data.name = DNAME),
class = "htest")
}
}
### test cases:
## SMR, Welsh Nickel workers
## poisson.test(137, 24.19893)
## eba1977, compare Fredericia to other three cities for ages 55-59
## poisson.test(c(11,6+8+7),c(800, 1083+1050+878))