msn.mle <- function(X,
y,
freq,
start,
trace = FALSE,
algorithm = c("nlminb", "Nelder-Mead", "BFGS", "CG", "SANN"),
control = list())
{
y <- data.matrix(y)
if (missing(X))
X <- rep(1, nrow(y))
else {
if (!is.numeric(X))
stop("X must be numeric")
}
if (missing(freq))
freq <- rep(1, nrow(y))
algorithm <- match.arg(algorithm)
X <- data.matrix(X)
k <- ncol(y)
n <- sum(freq)
m <- ncol(X)
y.names <- dimnames(y)[[2]]
x.names <- dimnames(X)[[2]]
if (missing(start)) {
fit0 <- lm.fit(X, y, method = "qr")
beta <- as.matrix(coef(fit0))
res <- resid(fit0)
a <- msn.moment.fit(res)
Omega <- a$Omega
omega <- a$omega
alpha <- a$alpha
if (!a$admissible)
alpha <- alpha / (1 + max(abs(alpha)))
beta[1,] <- beta[1,] - omega * a$delta * sqrt(2 / pi)
}
else{
beta <- start$beta
Omega <- start$Omega
alpha <- start$alpha
omega <- sqrt(diag(Omega))
}
al.om <- alpha / omega
if (trace) {
cat("Initial parameters:\n")
print(cbind(t(beta), al.om, Omega))
}
param <- c(beta, al.om)
dev <- msn.dev(param, X, y, freq)
if (algorithm == "nlminb") {
opt <- nlminb(
param,
msn.dev,
msn.dev.grad,
control = control,
X = X,
y = y,
freq = freq,
trace = trace
)
opt$value <- opt$objective
}
else{
opt <- optim(
param,
fn = msn.dev,
gr = msn.dev.grad,
method = algorithm,
control = control,
X = X,
y = y,
freq = freq,
trace = trace
)
}
if (trace)
cat(paste("Message from optimization routine:", opt$message, "\n"))
logL <- opt$value / (-2)
beta <- matrix(opt$par[1:(m * k)], m, k)
dimnames(beta)[2] <- list(y.names)
dimnames(beta)[1] <- list(x.names)
al.om <- opt$par[(m * k + 1):(m * k + k)]
xi <- X %*% beta
Omega <- t(y - xi) %*% (freq * (y - xi)) / n
omega <- sqrt(diag(Omega))
alpha <- al.om * omega
param <- cbind(omega, alpha)
dimnames(Omega) <- list(y.names, y.names)
dimnames(param)[1] <- list(y.names)
info <-
num.deriv2(
opt$par,
FUN = "msn.dev.grad",
X = X,
y = y,
freq = freq
) / 2
if (all(is.finite(info))) {
qr.info <- qr(info)
info.ok <- (qr.info$rank == length(param))
}
else
info.ok <- FALSE
if (info.ok) {
se2 <- diag(solve(qr.info))
if (min(se2) < 0)
se <- NA
else {
se <- sqrt(se2)
se <- sqrt(diag(solve(info)))
se.beta <- matrix(se[1:(m * k)], m, k)
se.alpha <- se[(m * k + 1):(m * k + k)] * omega
dimnames(se.beta)[2] <- list(y.names)
dimnames(se.beta)[1] <- list(x.names)
se <- list(beta = se.beta,
alpha = se.alpha,
info = info)
}
}
else
se <- NA
dp <- list(beta = beta,
Omega = Omega,
alpha = alpha)
opt$name <- algorithm
list(
call = match.call(),
dp = dp,
logL = logL,
se = se,
algorithm = opt
)
}
sn.cumulants <-
function(location = 0,
scale = 1,
shape = 0,
dp = NULL,
n = 4)
{
cumulants.half.norm <- function(n = 4) {
n <- max(n, 2)
n <- as.integer(2 * ceiling(n / 2))
half.n <- as.integer(n / 2)
m <- 0:(half.n - 1)
a <- sqrt(2 / pi) / (gamma(m + 1) * 2 ^ m * (2 * m + 1))
signs <- rep(c(1,-1), half.n)[1:half.n]
a <- as.vector(rbind(signs * a, rep(0, half.n)))
coeff <- rep(a[1], n)
for (k in 2:n) {
ind <- 1:(k - 1)
coeff[k] <- a[k] - sum(ind * coeff[ind] * a[rev(ind)] /
k)
}
kappa <- coeff * gamma((1:n) + 1)
kappa[2] <- 1 + kappa[2]
return(kappa)
}
if (!is.null(dp)) {
if (!missing(shape))
stop("You cannot set both component parameters and dp")
location <- dp[1]
scale <- dp[2]
shape <- dp[3]
}
par <- cbind(location, scale, shape)
delta <- par[, 3] / sqrt(1 + par[, 3] ^ 2)
n0 <- n
n <- max(n, 2)
kv <- cumulants.half.norm(n)
if (length(kv) > n)
kv <- kv[-(n + 1)]
kv[2] <- kv[2] - 1
kappa <-
outer(delta, 1:n, "^") * matrix(rep(kv, nrow(par)), ncol = n, byrow = TRUE)
kappa[, 2] <- kappa[, 2] + 1
kappa <- kappa * outer(par[, 2], (1:n), "^")
kappa[, 1] <- kappa[, 1] + par[, 1]
kappa[, 1:n0, drop = TRUE]
}
T.Owen <- function(h,
a,
jmax = 50,
cut.point = 6)
{
T.int <- function(h, a, jmax, cut.point)
{
fui <- function(h, i)
(h ^ (2 * i)) / ((2 ^ i) * gamma(i + 1))
seriesL <- seriesH <- NULL
i <- 0:jmax
low <- (h <= cut.point)
hL <- h[low]
hH <- h[!low]
L <- length(hL)
if (L > 0) {
b <- outer(hL, i, fui)
cumb <- apply(b, 1, cumsum)
b1 <- exp(-0.5 * hL ^ 2) * t(cumb)
matr <- matrix(1, jmax + 1, L) - t(b1)
jk <- rep(c(1,-1), jmax)[1:(jmax + 1)] / (2 * i + 1)
matr <- t(matr * jk) %*% a ^ (2 * i + 1)
seriesL <- (atan(a) - as.vector(matr)) / (2 * pi)
}
if (length(hH) > 0)
seriesH <- atan(a) * exp(-0.5 * (hH ^ 2) * a / atan(a)) *
(1 + 0.00868 * (hH ^ 4) * a ^ 4) / (2 * pi)
series <- c(seriesL, seriesH)
id <- c((1:length(h))[low], (1:length(h))[!low])
series[id] <- series # re-sets in original order
series
}
if (!is.vector(a) |
length(a) > 1)
stop("a must be a vector of length 1")
if (!is.vector(h))
stop("h must be a vector")
aa <- abs(a)
ah <- abs(h)
if (is.na(aa))
stop("parameter 'a' is NA")
if (aa == Inf)
return(0.5 * pnorm(-ah))
if (aa == 0)
return(rep(0, length(h)))
na <- is.na(h)
inf <- (ah == Inf)
ah <- replace(ah, (na | inf), 0)
if (aa <= 1)
owen <- T.int(ah, aa, jmax, cut.point)
else
owen <- 0.5 * pnorm(ah) + pnorm(aa * ah) * (0.5 - pnorm(ah)) -
T.int(aa * ah, (1 / aa), jmax, cut.point)
owen <- replace(owen, na, NA)
owen <- replace(owen, inf, 0)
return(owen * sign(a))
}
cp.to.dp <- function(param) {
## converts centred parameters cp=(mu,sigma,gamma1)
## to direct parameters dp=(xi,omega,lambda)
## Note: mu can be m-dimensional, the other must be scalars
b <- sqrt(2 / pi)
m <- length(param) - 2
gamma1 <- param[m + 2]
if (abs(gamma1) > 0.995271746431)
stop("abs(gamma1)> 0.995271746431")
A <- sign(gamma1) * (abs(2 * gamma1 / (4 - pi))) ^ (1 / 3)
delta <- A / (b * sqrt(1 + A ^ 2))
lambda <- delta / sqrt(1 - delta ^ 2)
E.Z <- b * delta
sd.Z <- sqrt(1 - E.Z ^ 2)
location <- param[1:m]
location[1] <- param[1] - param[m + 1] * E.Z / sd.Z
scale <- param[m + 1] / sd.Z
dp <- c(location, scale, lambda)
names(dp)[(m + 1):(m + 2)] <- c("scale", "shape")
if (m == 1)
names(dp)[1] <- "location"
dp
}
dp.to.cp <- function(param) {
## converts 'direct' dp=(xi,omega,lambda) to 'centred' cp=(mu,sigma,gamma1)
m <- length(param) - 2
omega <- param[m + 1]
lambda <- param[m + 2]
mu.Z <- lambda * sqrt(2 / (pi * (1 + lambda ^ 2)))
s.Z <- sqrt(1 - mu.Z ^ 2)
gamma1 <- 0.5 * (4 - pi) * (mu.Z / s.Z) ^ 3
sigma <- omega * s.Z
mu <- param[1:m]
mu[1] <- param[1] + sigma * mu.Z / s.Z
cp <- c(mu, sigma, gamma1)
names(cp)[(m + 1):(m + 2)] <- c("s.d.", "skewness")
if (m == 1)
names(cp)[1] <- "mean"
cp
}
zeta <- function(k, x) {
# k integer in (0,5)
if (k < 0 | k > 5 | k != round(k))
return(NULL)
k <- round(k)
na <- is.na(x)
x <- replace(x, na, 0)
x2 <- x ^ 2
z <- switch(
k + 1,
pnorm(x, log.p = TRUE) + log(2),
ifelse(x > (-50), exp(
dnorm(x, log = TRUE) - pnorm(x, log.p = TRUE)
), -x / (
1 - 1 / (x2 + 2) + 1 / ((x2 + 2) * (x2 + 4))
- 5 / ((x2 + 2) * (x2 + 4) * (x2 + 6))
+ 9 / ((x2 + 2) * (x2 + 4) * (x2 + 6) * (x2 +
8))
- 129 / ((x2 + 2) * (x2 + 4) * (x2 + 6) * (x2 +
8) * (x2 + 10))
)),
(-zeta(1, x) * (x + zeta(1, x))),
(-zeta(2, x) * (x + zeta(1, x)) - zeta(1, x) * (1 + zeta(2, x))),
(-zeta(3, x) * (x + 2 * zeta(1, x)) - 2 * zeta(2, x) * (1 +
zeta(2, x))),
(
-zeta(4, x) * (x + 2 * zeta(1, x)) - zeta(3, x) * (3 + 4 * zeta(2, x))
- 2 * zeta(2, x) * zeta(3, x)
),
NULL
)
neg.inf <- (x == -Inf)
if (any(neg.inf))
z <- switch(
k + 1,
z,
replace(z, neg.inf, Inf),
replace(z, neg.inf, -1),
replace(z, neg.inf, 0),
replace(z, neg.inf, 0),
replace(z, neg.inf, 0),
NULL
)
if (k > 1)
z <- replace(z, x == Inf, 0)
replace(z, na, NA)
}
sn.em <-
function(X,
y,
fixed,
p.eps = 1e-4,
l.eps = 1.e-2,
trace = FALSE,
data = FALSE)
{
n <- length(y)
if (missing(X))
X <- matrix(rep(1, n), n, 1)
nc <- ncol(X)
if (missing(fixed))
fixed <- rep(NA, 3)
if (all(!is.na(fixed)))
stop("all parameter are fixed")
if (is.na(fixed[3]))
iter <- (1 - log(l.eps, 10))
else
iter <- 1
qrX <- qr(X)
beta <- qr.coef(qrX, y)
xi <- m <- qr.fitted(qrX, y)
omega <- fixed[2]
lambda <- fixed[3]
delta <- lambda / sqrt(1 + lambda ^ 2)
s <- sqrt(sum((y - xi) ^ 2) / n)
if (is.na(fixed[3])) {
gamma1 <- sum((y - m) ^ 3) / (n * s ^ 3)
a <- sign(gamma1) * (2 * abs(gamma1) / (4 - pi)) ^ 0.33333
delta <- sqrt(pi / 2) * a / sqrt(1 + a ^ 2)
if (abs(delta) >= 1)
delta <- sign(delta) / (1 + 1 / n)
lambda <- delta / sqrt(1 - delta ^ 2)
}
mean.Z <- sqrt(2 / pi) * delta
sd.Z <- sqrt(1 - mean.Z ^ 2)
if (is.na(fixed[2]))
omega <- s / sd.Z
if (is.na(fixed[1]))
xi <- m - s * mean.Z / sd.Z
old.par <- c(beta, omega, lambda)
diverge <- 1
incr.logL <- Inf
logL <- -Inf
while (diverge > p.eps | incr.logL > l.eps) {
## E-step
v <- (y - xi) / omega
p <- zeta(1, lambda * v)
u1 <- omega * (delta * v + p * sqrt(1 - delta ^ 2))
u2 <-
omega ^ 2 * ((delta * v) ^ 2 + (1 - delta ^ 2) + p * v * delta * sqrt(1 -
delta ^ 2))
## M-step
for (i in 1:iter) {
beta <- qr.coef(qrX, y - delta * u1)
xi <- qr.fitted(qrX, y - delta * u1)
d <- y - xi
Q <- sum(d ^ 2 - 2 * delta * d * u1 + u2)
if (is.na(fixed[2]))
omega <- sqrt(Q / (2 * n * (1 - delta ^ 2)))
r <- 2 * sum(d * u1) / Q
if (is.na(fixed[3]))
delta <- (sqrt((2 * r) ^ 2 + 1) - 1) / (2 * r)
}
## convergence? # lambda<-lambda.of(delta)
lambda <- delta / sqrt(1 - delta ^ 2)
param <- c(beta, omega, lambda)
names(param)[(nc + 1):(nc + 2)] <- c("scale", "shape")
if (nc == 1 & all(X == 1))
names(param)[1] <- "location"
else
names(param)[1:nc] <- colnames(X)
diverge <-
sum(abs(param - old.par) / (1 + abs(old.par))) / (nc +
2)
old.par <- param
new.logL <- sum(dsn(y, xi, omega, lambda, log = TRUE))
incr.logL <- new.logL - logL
logL <- new.logL
if (trace)
print(c(param, logL), digits = 5)
}
cp <- dp.to.cp(param)
result <- list(dp = param, cp = cp, logL = logL)
if (data)
result$data <- list(X = X,
y = y,
residuals = d / omega)
result
}
##-------------------
gamma1.to.lambda <- function(gamma1) {
max.gamma1 <- 0.5 * (4 - pi) * (2 / (pi - 2)) ^ 1.5
na <- (abs(gamma1) > max.gamma1)
if (any(na))
warning("NAs generated")
gamma1 <- replace(gamma1, na, NA)
a <- sign(gamma1) * (2 * abs(gamma1) / (4 - pi)) ^ 0.33333
delta <- sqrt(pi / 2) * a / sqrt(1 + a ^ 2)
lambda <- delta / sqrt(1 - delta ^ 2)
as.vector(lambda)
}
sn.2logL.profile <- function(X = matrix(rep(1, n)),
y,
param.range = c(sqrt(var(y)) * c(2 / 3, 3 / 2), -0.95, 0.95),
use.cp = TRUE,
npts = 51 %/% d,
plot.it = TRUE,
...)
{
# plot 1D or 2D profile deviance (=-2logL) using either parameters
## if(plot.it & !exists(.Device)) stop("Device not active")
n <- length(y)
d <- round(length(param.range) / 2)
if ((d != 1) &
(d != 2))
stop(" length(param.range) must be either 2 or 4")
if (d == 1) {
param1 <- seq(param.range[1], param.range[2], length = npts)
llik <- param2 <- rep(NA, npts)
}
else{
param1 <- seq(param.range[1], param.range[2], length = npts)
param2 <- seq(param.range[3], param.range[4], length = npts)
llik <- matrix(NA, npts, npts)
}
if (use.cp) {
if (d == 1) {
gamma1 <- param1
sigma <- param2
xlab <- "gamma1"
ylab <- ""
}
else {
sigma <- param1
gamma1 <- param2
xlab <- "sigma"
ylab <- "gamma1"
}
if (max(abs(gamma1)) > 0.9952717)
stop("abs(gamma1)>0.9952717")
lambda <- gamma1.to.lambda(gamma1)
sc <- sqrt(1 - (2 / pi) * lambda ^ 2 / (1 + lambda ^ 2))
}
else{
# use dp
if (d == 1) {
lambda <- param1
omega <- param2
xlab <- "alpha"
ylab <- ""
}
else {
omega <- param1
sc <- rep(1, npts)
lambda <- param2
xlab <- "omega"
ylab <- "alpha"
}
}
cat(c("Running until", npts, ":"))
for (i in 1:npts) {
cat(" ")
cat(i)
if (d == 1) {
a <- sn.em(X, y, fixed = c(NA, NA, lambda[i]), ...)
llik[i] <- a$logL
}
else{
for (j in 1:npts) {
a <- sn.em(X, y, fixed = c(NA, param1[i] / sc[j], lambda[j]), ...)
llik[i, j] <- a$logL
}
}
}
cat("\n")
##if(plot)
f <- 2 * (llik - max(llik))
if (plot.it) {
if (d == 1)
plot(param1,
f,
type = "l",
xlab = xlab,
ylab = "profile deviance")
else
contour(
param1,
param2,
f,
labcex = 0.5,
xlab = xlab,
ylab = ylab,
levels = -c(0.57, 1.37, 2.77, 4.6, 5.99, 9.2),
labels = c(0.25, 0.5, 0.75, 0.90, 0.95, 0.99)
)
title(main = paste(
"Dataset:",
deparse(substitute(y)),
"\nProfile deviance function",
sep = " "
))
}
invisible(list(
param1 = param1,
param2 = param2,
param.names = c(xlab, ylab),
two.logL = f,
maximum = 2 * max(llik)
))
}
sn.mle <-
function(X,
y,
cp,
plot.it = TRUE,
trace = FALSE,
method = "L-BFGS-B",
control = list(maxit = 100))
{
xlab <- deparse(substitute(y))
if (!is.null(dim(y))) {
if (min(dim(y)) == 1)
y <- as.vector(y)
else
stop("y must be a vector")
}
n <- length(y)
if (missing(X)) {
X <- as.matrix(rep(1, n))
cp.names <- "mean"
}
else{
if (is.null(colnames(X)))
cp.names <-
outer(deparse(substitute(X)), as.character(1:ncol(X)),
paste, sep = ".")
else
cp.names <- colnames(X)
}
cp.names <- c(cp.names, "s.d.", "skewness")
m <- ncol(X)
if (missing(cp)) {
qrX <- qr(X)
s <- sqrt(sum(qr.resid(qrX, y) ^ 2) / n)
gamma1 <- sum(qr.resid(qrX, y) ^ 3) / (n * s ^ 3)
if (abs(gamma1) > 0.99527)
gamma1 <- sign(gamma1) * 0.95
cp <- c(qr.coef(qrX, y), s, gamma1)
}
else{
if (length(cp) != (m + 2))
stop("ncol(X)+2 != length(cp)")
}
opt <- optim(
cp,
fn = sn.dev,
gr = sn.dev.gh,
method = method,
lower = c(-rep(Inf, m), 10 * .Machine$double.eps, -0.99527),
upper = c(rep(Inf, m), Inf, 0.99527),
control = control,
X = X,
y = y,
trace = trace,
hessian = FALSE
)
cp <- opt$par
if (trace) {
cat(paste("Message from optimization routine:", opt$message, "\n"))
cat("estimates (cp): ", cp, "\n")
}
if (abs(cp[m + 2]) > 0.9952717) {
if (trace)
cat("optim searched outside admissible range - restarted\n")
cp[m + 2] <- sign(cp[m + 2]) * runif(1)
mle <- sn.mle(X, y, cp, plot.it, trace, method, control)
cp <- mle$cp
}
logL <- (-opt$value) / 2
info <-
attr(sn.dev.gh(cp, X, y, trace = FALSE, hessian = TRUE), "hessian") / 2
## se <- sqrt(diag(solve(info)))
if (all(is.finite(info)))
{
qr.info <- qr(info)
info.ok <- (qr.info$rank == length(cp))
}
else
info.ok <- FALSE
if (info.ok) {
se2 <- diag(solve.qr(qr.info))
se <- sqrt(ifelse(se2 >= 0, se2, NA))
}
else
se <- rep(NA, length(cp))
if (plot.it) {
dp0 <- cp.to.dp(cp)
if (all(X == rep(1, n)))
y0 <- y
else {
y0 <- as.vector(y - X %*% dp0[1:m])
dp0 <- c(0, dp0[m + 1], dp0[m + 2])
xlab <- "residuals"
}
x <-
seq(min(pretty(y0, 10)), max(pretty(y0, 10)), length = 200)
pdf.sn <- dsn(x, dp0[1], dp0[2], dp0[3])
h <- hist(y0, breaks = "FD", plot = FALSE)
hist(
y0,
freq = FALSE,
breaks = "FD",
xlim = c(min(x), max(x)),
xlab = xlab,
main = xlab,
ylim = c(0, max(pdf.sn, h$density))
)
if (n < 101)
points(y0, rep(0, n), pch = 1)
curve(dsn(x, dp0[1], dp0[2], dp0[3]), add = TRUE, col = 2)
}
names(cp) <- names(se) <- cp.names
list(
call = match.call(),
cp = cp,
se = se,
info = info,
logL = logL,
optim = opt
)
}
sn.dev <- function(cp, X, y, trace = FALSE)
{
# -2*logL for centred parameters
m <- ncol(X)
if (abs(cp[m + 2]) > 0.9952717) {
warning("optim search in abs(cp[m+2])> 0.9952717, value adjusted")
cp[m + 2] <- 0.9952717 * sign(cp[m + 2])
}
dp <- as.vector(cp.to.dp(cp))
location <- as.vector(X %*% as.matrix(dp[1:m]))
logL <- sum(dsn(y, location, dp[m + 1], dp[m + 2], log = TRUE))
if (trace) {
cat("sn.dev: (cp,dev) =", format(c(cp, -2 * logL)))
}
return(-2 * logL)
}
sn.dev.gh <- function(cp,
X,
y,
trace = FALSE,
hessian = FALSE)
{
## computes gradient and hessian of dev=-2*logL for centred parameters
## (and observed information matrix);
m <- ncol(X)
n <- nrow(X)
np <- m + 2
if (abs(cp[m + 2]) > 0.9952717) {
warning("optim search in abs(cp[m+2])> 0.9952717, value adjusted")
cp[m + 2] <- 0.9952717 * sign(cp[m + 2])
}
score <- rep(NA, np)
info <- matrix(NA, np, np)
beta <- cp[1:m]
sigma <- cp[m + 1]
gamma1 <- cp[m + 2]
lambda <- gamma1.to.lambda(gamma1)
## dp<-cp.to.dp(c(beta,sigma,gamma1))
## info.dp <- sn.info(dp,y)$info.dp
mu <- as.vector(X %*% as.matrix(beta))
d <- y - mu
r <- d / sigma
E.Z <- lambda * sqrt(2 / (pi * (1 + lambda ^ 2)))
s.Z <- sqrt(1 - E.Z ^ 2)
z <- E.Z + s.Z * r
p1 <- as.vector(zeta(1, lambda * z))
p2 <- as.vector(zeta(2, lambda * z))
omega <- sigma / s.Z
w <- lambda * p1 - E.Z
DE.Z <- sqrt(2 / pi) / (1 + lambda ^ 2) ^ 1.5
Ds.Z <- (-E.Z / s.Z) * DE.Z
Dz <- DE.Z + r * Ds.Z
DDE.Z <- (-3) * E.Z / (1 + lambda ^ 2) ^ 2
DDs.Z <-
-((DE.Z * s.Z - E.Z * Ds.Z) * DE.Z / s.Z ^ 2 + E.Z * DDE.Z /
s.Z)
DDz <- DDE.Z + r * DDs.Z
score[1:m] <-
omega ^ (-2) * t(X) %*% as.matrix(y - mu - omega * w)
score[m + 1] <-
(-n) / sigma + s.Z * sum(d * (z - p1 * lambda)) / sigma ^
2
score[m + 2] <-
score.l <-
n * Ds.Z / s.Z - sum(z * Dz) + sum(p1 * (z + lambda * Dz))
Dg.Dl <-
1.5 * (4 - pi) * E.Z ^ 2 * (DE.Z * s.Z - E.Z * Ds.Z) / s.Z ^
4
R <- E.Z / s.Z
Te <- sqrt(2 / pi - (1 - 2 / pi) * R ^ 2)
Dl.Dg <-
2 * (Te / (Te * R) ^ 2 + (1 - 2 / pi) / Te ^ 3) / (3 * (4 -
pi))
R. <- 2 / (3 * R ^ 2 * (4 - pi))
T. <- (-R) * R. * (1 - 2 / pi) / Te
DDl.Dg <-
(-2 / (3 * (4 - pi))) * (T. / (R * Te) ^ 2 + 2 * R. / (Te * R ^ 3) + 3 *
(1 - 2 / pi) * T. / Te ^ 4)
score[m + 2] <-
score[m + 2] / Dg.Dl # convert deriv wrt lamda to gamma1
gradient <- (-2) * score
if (hessian) {
info[1:m, 1:m] <-
omega ^ (-2) * t(X) %*% ((1 - lambda ^ 2 * p2) * X)
info[1:m, m + 1] <- info[m + 1, 1:m] <-
s.Z * t(X) %*% as.matrix((z - lambda * p1) + d * (1 - lambda ^
2 * p2) *
s.Z / sigma) / sigma ^ 2
info[m + 1, m + 1] <-
(-n) / sigma ^ 2 + 2 * s.Z * sum(d * (z - lambda * p1)) / sigma ^ 3 +
s.Z ^ 2 * sum(d * (1 - lambda ^ 2 * p2) * d) / sigma ^ 4
info[1:m, m + 2] <- info[m + 2, 1:m] <-
t(X) %*% (-2 * Ds.Z * d / omega + Ds.Z * w + s.Z * (p1 + lambda *
p2 * (z + lambda * Dz)
- DE.Z)) / sigma
info[m + 1, m + 2] <- info[m + 2, m + 1] <-
-sum(d * (Ds.Z * (z - lambda * p1) + s.Z * (Dz - p1 - p2 * lambda *
(z + lambda * Dz)))) / sigma ^ 2
info[m + 2, m + 2] <-
(n * (-DDs.Z * s.Z + Ds.Z ^ 2) / s.Z ^ 2 + sum(Dz ^ 2 + z * DDz) -
sum(p2 * (z + lambda * Dz) ^ 2) - sum(p1 * (2 *
Dz + lambda * DDz)))
info[np,] <-
info[np,] / Dg.Dl # convert info wrt lamda to gamma1
info[, np] <-
info[, np] * Dl.Dg # an equivalent form of the above
info[np, np] <- info[np, np] - score.l * DDl.Dg
attr(gradient, "hessian") <- 2 * info
}
if (trace) {
cat("sn.dev.gh: gradient=")
print(-2 * score)
}
return(gradient)
}
##
dmsn <-
function(x,
xi = rep(0, length(alpha)),
Omega,
alpha,
dp = NULL,
log = FALSE)
{
if (!(missing(alpha) & missing(Omega)) && !is.null(dp))
stop("You cannot set both component parameters and dp")
if (!is.null(dp)) {
if (!is.null(dp$xi))
xi <- dp$xi
else {
if (!is.null(dp$beta))
xi <- as.vector(dp$beta)
}
Omega <- dp$Omega
alpha <- dp$alpha
}
d <- length(alpha)
Omega <- matrix(Omega, d, d)
x <- if (is.vector(x))
matrix(x, 1, d)
else
data.matrix(x)
if (is.vector(xi))
xi <- outer(rep(1, nrow(x)), xi)
X <- t(x - xi)
Q <- apply((solvePD(Omega) %*% X) * X, 2, sum)
L <- as.vector(t(X / sqrt(diag(Omega))) %*% as.matrix(alpha))
logDet <- sum(logb(abs(diag(qr(
Omega
)$qr))))
logPDF <- (logb(2) - 0.5 * Q + pnorm(L, log.p = TRUE)
- 0.5 * (d * logb(2 * pi) + logDet))
if (log)
logPDF
else
exp(logPDF)
}
rmsn <-
function(n = 1,
xi = rep(0, length(alpha)),
Omega,
alpha,
dp = NULL)
{
# generates SN_d(xi,Omega,alpha) variates using transformation method
if (!(missing(alpha) & missing(Omega)) && !is.null(dp))
stop("You cannot set both component parameters and dp")
if (!is.null(dp)) {
if (!is.null(dp$xi))
xi <- dp$xi
else
if (!is.null(dp$beta))
xi <- as.vector(dp$beta)
Omega <- dp$Omega
alpha <- dp$alpha
}
d <- length(alpha)
Z <- msn.quantities(xi, Omega, alpha)
y <- matrix(rnorm(n * d), n, d) %*% chol(Z$Psi)
## each row of y is N_d(0,Psi)
abs.y0 <- abs(rnorm(n))
abs.y0 <- matrix(rep(abs.y0, d), ncol = d)
delta <- Z$delta
z <- delta * t(abs.y0) + sqrt(1 - delta ^ 2) * t(y)
y <- t(xi + Z$omega * z)
attr(y, "parameters") <- list(xi = xi,
Omega = Omega,
alpha = alpha)
return(y)
}
pmsn <-
function(x,
xi = rep(0, length(alpha)),
Omega,
alpha,
dp = NULL,
...)
{
if (!(missing(alpha) & missing(Omega)) && !is.null(dp))
stop("You cannot set both component parameters and dp")
if (!is.null(dp)) {
if (!is.null(dp$xi))
xi <- dp$xi
else
if (!is.null(dp$beta))
xi <- as.vector(dp$beta)
Omega <- dp$Omega
alpha <- dp$alpha
}
pmst(
x,
xi = xi,
Omega = Omega,
alpha = alpha,
df = Inf,
...
)
}
dsn2.plot <- function(x, y, xi, Omega, alpha, dp = NULL, ...)
{
# plot bivariate density SN_2(xi,Omega,alpha) computed at (x,y) grid
if (!is.null(dp)) {
if (!is.null(dp$xi))
xi <- dp$xi
else
if (!is.null(dp$beta))
xi <- as.vector(dp$beta)
Omega <- dp$Omega
alpha <- dp$alpha
df <- dp$df
}
if (any(dim(Omega) != c(2, 2)))
stop("dim(Omega) != c(2,2)")
nx <- length(x)
ny <- length(y)
xoy <-
cbind(rep(x, ny), as.vector(matrix(y, nx, ny, byrow = TRUE)))
X <- matrix(xoy, nx * ny, 2, byrow = FALSE)
pdf <- dmsn(X, xi, Omega, alpha)
pdf <- matrix(pdf, nx, ny)
contour(x, y, pdf, ...)
invisible(list(
x = x,
y = y,
density = pdf,
xi = xi,
Omega = Omega,
alpha = alpha
))
}
msn.quantities <-
function(xi = rep(0, length(alpha)),
Omega,
alpha,
dp = NULL)
{
# 21-12-1997; computes various quantities related to SN_d(xi,Omega,alpha)
if (!is.null(dp)) {
if (any(!missing(xi) | !missing(Omega) | !missing(alpha)))
stop("you cat set either dp or its components, but not both")
xi <- as.vector(dp$xi)
if (is.null(dp$xi))
xi <- as.vector(dp$beta)
Omega <- dp$Omega
alpha <- dp$alpha
}
d <- length(alpha)
Omega <- as.matrix(Omega)
if (length(xi) != d | any(dim(Omega) != c(d, d)))
stop("dimensions of arguments do not match")
omega <- sqrt(diag(Omega))
O.cor <- cov2cor(Omega)
tmp <-
as.vector(sqrt(1 + t(as.matrix(alpha)) %*% O.cor %*% alpha))
delta <- as.vector(O.cor %*% alpha) / tmp
lambda <- delta / sqrt(1 - delta ^ 2)
D <- diag(sqrt(1 + lambda ^ 2), d, d)
Psi <- D %*% (O.cor - outer(delta, delta)) %*% D
Psi <- (Psi + t(Psi)) / 2
O.inv <- solvePD(Omega)
O.pcor <- -cov2cor(O.inv)
O.pcor[cbind(1:d, 1:d)] <- 1
muZ <- delta * sqrt(2 / pi)
muY <- xi + omega * muZ
Sigma <-
diag(omega, d, d) %*% (O.cor - outer(muZ, muZ)) %*% diag(omega, d, d)
Sigma <- (Sigma + t(Sigma)) / 2
cv <- muZ / sqrt(1 - muZ ^ 2)
gamma1 <- 0.5 * (4 - pi) * cv ^ 3
list(
xi = xi,
Omega = Omega,
alpha = alpha,
omega = omega,
mean = muY,
variance = Sigma,
Omega.conc = O.inv,
Omega.cor = O.cor,
Omega.pcor = O.pcor,
lambda = lambda,
Psi = Psi,
delta = delta,
skewness = gamma1
)
}
msn.conditional <- function(xi = rep(0, length(alpha)),
Omega,
alpha,
fixed.comp,
fixed.values,
dp = NULL)
{
## conditional Multivariate SN (6/11/1997).
## Given a rv Y ~ SN_d(xi,Omega,alpha), this function computes cumulants of
## conditrional distribution, given that the fixed.com take on fixed.values;
## then it finds MSN with matching cumulants.
Diag <- function(x)
diag(x, nrow = length(x), ncol = length(x))
msqrt <- function(A)
Diag(sqrt(diag(as.matrix(A))))
imsqrt <- function(A)
Diag(1 / sqrt(diag(as.matrix(A))))
if (!is.null(dp)) {
if (!is.null(dp$xi))
xi <- dp$xi
else
if (!is.null(dp$beta))
xi <- as.vector(dp$beta)
Omega <- dp$Omega
alpha <- dp$alpha
}
d <- length(alpha)
h <- length(fixed.comp)
if (any(dim(Omega) != c(d, d)) |
length(xi) != d | h != length(fixed.values))
stop("dimensions of parameters do not match")
fc <- fixed.comp
O <- as.matrix(Omega)
O11 <- O[fc, fc, drop = FALSE]
O12 <- O[fc,-fc, drop = FALSE]
O21 <- O[-fc, fc, drop = FALSE]
O22 <- O[-fc,-fc, drop = FALSE]
o22 <- sqrt(diag(O22))
inv.O11 <- solvePD(O11)
xi1 <- xi[fc, drop = FALSE]
xi2 <- xi[-fc, drop = FALSE]
alpha1 <- matrix(alpha[fc])
alpha2 <- matrix(alpha[-fc])
O22.1 <- O22 - O21 %*% inv.O11 %*% O12
O22.b <- imsqrt(O22) %*% O22.1 %*% imsqrt(O22)
xi.c <-
xi2 + as.vector(O21 %*% inv.O11 %*% matrix(fixed.values - xi1))
a <- sqrt(1 + as.vector(t(alpha2) %*% O22.b %*% alpha2))
alpha.b <-
(alpha1 + msqrt(O11) %*% inv.O11 %*% O12 %*% (alpha2 / o22)) / a
d2 <- as.vector(O22.b %*% alpha2) / a
x0 <- sum(alpha.b * (fixed.values - xi1) / sqrt(diag(O11)))
E.c <- xi.c + zeta(1, x0) * o22 * d2
var.c <- O22.1 + zeta(2, x0) * outer(o22 * d2, o22 * d2)
gamma1 <-
zeta(3, x0) * d2 ^ 3 / diag(O22.b + zeta(2, x0) * d2 ^ 2) ^
1.5
cum <- list(as.vector(E.c), var.c, gamma1)
## cumulants are computed; now choose SN distn to fit them
a <- sign(gamma1) * (2 * abs(gamma1) / (4 - pi)) ^ 0.33333
E.z <- a / sqrt(1 + a ^ 2)
delta <- E.z * sqrt(pi / 2)
omega <- sqrt(diag(var.c) / (1 - E.z ^ 2))
O.new <- var.c + outer(omega * E.z, omega * E.z)
xi.new <- E.c - omega * E.z
B <- diag(1 / omega, d - h, d - h)
m <-
as.vector(solvePD(B %*% O.new %*% B) %*% as.matrix(delta))
a <- m / sqrt(1 - sum(delta * m))
## cum2<- msn.cumulants(xi.new,O.new,a)
list(
cumulants = cum,
fit = list(
xi = xi.new,
Omega = O.new,
alpha = a,
delta = delta
)
)
}
msn.marginal <- function(xi = rep(0, length(alpha)),
Omega,
alpha,
comp = 1:d,
dp = NULL)
{
# calcola parametri della marginale associata a comp di un SN_d
## cfr SJS 2003, p.131-2
if (!is.null(dp)) {
if (!is.null(dp$xi))
xi <- dp$xi
else
if (!is.null(dp$beta))
xi <- as.vector(dp$beta)
Omega <- dp$Omega
alpha <- dp$alpha
}
alpha <- as.vector(alpha)
d <- length(alpha)
xi <- as.vector(xi)
comp <- as.integer(comp)
if (length(xi) != d)
stop("parameter size not compatible")
if (all(dim(Omega) != c(d, d)))
stop("parameter size not compatible")
if (length(comp) < d) {
if (any(comp > d | comp < 1))
stop("comp makes no sense")
O <- cov2cor(Omega)
O11 <- O[comp, comp, drop = FALSE]
O12 <- O[comp,-comp, drop = FALSE]
O21 <- O[-comp, comp, drop = FALSE]
O22 <- O[-comp,-comp, drop = FALSE]
alpha1 <- matrix(alpha[comp], ncol = 1)
alpha2 <- matrix(alpha[-comp], ncol = 1)
O11_inv <- solvePD(O11)
O22.1 <- O22 - O21 %*% O11_inv %*% O12
a.sum <- as.vector(t(alpha2) %*% O22.1 %*% alpha2)
a.new <-
as.vector(alpha1 + O11_inv %*% O12 %*% alpha2) / sqrt(1 + a.sum)
result <-
list(xi = xi[comp],
Omega = Omega[comp, comp],
alpha = a.new)
}
else {
if (any(sort(comp) != (1:d)))
stop("comp makes no sense")
result <-
list(xi = xi[comp],
Omega = Omega[comp, comp],
alpha = alpha[comp])
}
if (!is.null(dp$tau))
result$tau <- dp$tau
result
}
msn.cond.plot <-
function(xi,
Omega,
alpha,
fixed.comp,
fixed.values,
n = 35)
{
# fa il grafico di Y_2|Y_1; assumiamo che dim(Y_2)= 2
msn.pdf2.aux <- function(x, y, xi, Omega, alpha, fc, fv)
{
nx <- length(x)
ny <- length(y)
FV <-
matrix(rep(fv, nx * ny), nx * ny, length(fv), byrow = TRUE)
X <- matrix(NA, nx * ny, length(alpha))
X[, fc] <- FV
xoy <-
cbind(rep(x, ny), as.vector(matrix(y, nx, ny, byrow = TRUE)))
X[,-fc] <- matrix(xoy, nx * ny, 2, byrow = FALSE)
pdf <- dmsn(X, xi, Omega, alpha)
matrix(pdf, nx, ny)
}
dsn2 <- function(x, y, d1, d2, omega)
{
u <- (x * (d1 - omega * d2) + y * (d2 - omega * d1)) /
sqrt((1 - omega ^ 2 - d1 ^ 2 - d2 ^ 2 + 2 * omega * d1 *
d2) * (1 - omega ^ 2))
pdfn2 <- exp(-0.5 * (x ^ 2 - 2 * omega * x * y + y ^ 2) / (1 -
omega ^ 2)) /
(2 * pi * sqrt(1 - omega ^ 2))
2 * pdfn2 * pnorm(u)
}
fc <- fixed.comp
fv <- fixed.values
cond <- msn.conditional(xi, Omega, alpha, fc, fv)
xi.c <- cond$fit$xi
O.c <- cond$fit$Omega
a.c <- cond$fit$alpha
if (any(dim(O.c) != c(2, 2)))
stop("length(alpha)-length(fixed.com)!=2")
scale1 <- sqrt(as.vector(O.c[1, 1]))
scale2 <- sqrt(as.vector(O.c[2, 2]))
delta <- cond$fit$delta
omega <- as.vector(O.c[1, 2]) / (scale1 * scale2)
x <- seq(xi.c[1] - 3 * scale1, xi.c[1] + 3 * scale1, length = n)
y <- seq(xi.c[2] - 3 * scale2, xi.c[2] + 3 * scale2, length = n)
plot(x, y, type = "n", main = "Conditional multivariate SN pdf")
z1 <- (x - xi.c[1]) / scale1
z2 <- (y - xi.c[2]) / scale2
pdf.fit <- outer(z1,
z2,
dsn2,
d1 = delta[1],
d2 = delta[2],
omega = omega) /
(scale1 * scale2)
cond$pdf <- list(x = x, y = y, f.fitted = pdf.fit)
levels <- pretty(pdf.fit, 5)
contour(x,
y,
pdf.fit,
levels = levels,
add = TRUE,
col = 2)
numer <- msn.pdf2.aux(x, y, xi, Omega, alpha, fc, fv)
marg <- msn.marginal(xi, Omega, alpha, fc)
denom <- dmsn(fv, marg$xi, marg$Omega, marg$alpha)
pdf.exact <- numer / as.vector(denom)
contour(
x,
y,
pdf.exact,
add = TRUE,
levels = levels,
col = 1,
lty = 4,
labcex = 0
)
legend(x[1],
y[length(y)],
c("approx", "exact"),
lty = c(1, 4),
col = c(2, 1))
cond$pdf$f.exact <- pdf.exact
cond$rel.error <- summary((pdf.fit - pdf.exact) / pdf.exact)
cond$abs.error <- summary(abs(pdf.fit - pdf.exact))
invisible(cond)
}
msn.moment.fit <- function(y)
{
# 31-12-1997: simple fit of MSN distribution usign moments
y <- as.matrix(y)
k <- ncol(y)
m.y <- apply(y, 2, mean)
var.y <- var(y)
y0 <- (t(y) - m.y) / sqrt(diag(var.y))
gamma1 <- apply(y0 ^ 3, 1, mean)
out <- (abs(gamma1) > 0.99527)
gamma1[out] <- sign(gamma1[out]) * 0.995
a <- sign(gamma1) * (2 * abs(gamma1) / (4 - pi)) ^ 0.33333
delta <- sqrt(pi / 2) * a / sqrt(1 + a ^ 2)
m.z <- delta * sqrt(2 / pi)
omega <- sqrt(diag(var.y) / (1 - m.z ^ 2))
Omega <- var.y + outer(omega * m.z, omega * m.z)
xi <- m.y - omega * m.z
O.cor <- cov2cor(Omega)
O.inv <- solvePD(O.cor)
tmp <- as.vector(1 - t(delta) %*% O.inv %*% delta)
if (tmp <= 0) {
tmp <- 0.0001
admissible <- FALSE
}
else
admissible <- TRUE
alpha <- as.vector(O.inv %*% delta) / sqrt(tmp)
list(
xi = xi,
Omega = Omega,
alpha = alpha,
Omega.cor = O.cor,
omega = omega,
delta = delta,
skewness = gamma1,
admissible = admissible
)
}
msn.fit <- function(X,
y,
freq,
plot.it = TRUE,
trace = FALSE,
...)
{
y.name <- deparse(substitute(y))
y.names <- dimnames(y)[[2]]
y <- as.matrix(y)
colnames(y) <- y.names
k <- ncol(y)
if (missing(freq))
freq <- rep(1, nrow(y))
n <- sum(freq)
if (missing(X)) {
X <- rep(1, nrow(y))
missing.X <- TRUE
}
else
missing.X <- FALSE
X <- as.matrix(X)
m <- ncol(X)
if (length(dimnames(y)[[2]]) == 0) {
dimnames(y) <-
list(NULL, outer("V", as.character(1:k), paste, sep = ""))
y.names <- as.vector(dimnames(y)[[2]])
}
qrX <- qr(X)
mle <- msn.mle(
X = X,
y = y,
freq = freq,
trace = trace,
...
)
mle$call <- match.call()
## print(mle$nlminb$message)
beta <- mle$dp$beta
Omega <- mle$dp$Omega
alpha <- mle$dp$alpha
omega <- sqrt(diag(Omega))
xi <- X %*% beta
if (plot.it & all(freq == rep(1, length(y)))) {
if (missing.X) {
y0 <- y
xi0 <- apply(xi, 2, mean)
}
else {
y0 <- y - xi
xi0 <- rep(0, k)
}
if (k > 1) {
opt <- options()
options(warn = -1)
pairs(
y0,
labels = y.names,
panel = function(x, y, Y, y.names, xi, Omega, alpha)
{
for (i in 1:length(alpha)) {
## if(y.names[i]==deparse(substitute(x))) Ix<-i
## if(y.names[i]==deparse(substitute(y))) Iy<-i
if (all(Y[, i] == x))
Ix <- i
if (all(Y[, i] == y))
Iy <- i
}
points(x, y)
marg <- msn.marginal(xi, Omega, alpha, c(Ix, Iy))
xi.marg <- marg$xi
Omega.marg <- marg$Omega
alpha.marg <- marg$alpha
x1 <- seq(min(x), max(x), length = 30)
x2 <- seq(min(y), max(y), length = 30)
dsn2.plot(x1,
x2,
xi.marg,
Omega.marg,
alpha.marg,
add = TRUE,
col = 2)
},
## end "panel" function
Y = y0,
y.names = y.names,
xi = xi0,
Omega = Omega,
alpha = alpha
)
options(opt)
}
else{
# plot for case k=1
y0 <- as.vector(y0)
x <- seq(min(pretty(y0, 10)), max(pretty(y0, 10)), length =
100)
if (missing.X) {
dp0 <- c(xi0, omega, alpha)
xlab <- y.name
}
else {
dp0 <- c(0, omega, alpha)
xlab <- "residuals"
}
hist(
y0,
prob = TRUE,
breaks = "FD",
xlab = xlab,
ylab = "density"
)
lines(x, dsn(x, dp0[1], dp0[2], dp0[3]))
if (length(y) < 101)
points(y0, rep(0, n), pch = 1)
title(y.name)
}
cat("Press <Enter> to continue...")
readline()
par(mfrow = c(1, 2))
pp <- qchisq((1:n) / (n + 1), k)
## Xb <- qr.fitted(qrX,y)
res <- qr.resid(qrX, y)
rad.n <-
apply(res * (res %*% solvePD(var(res))), 1, sum)
rad.sn <-
apply((y - xi) * ((y - xi) %*% solvePD(Omega)), 1, sum)
plot(
pp,
sort(rad.n),
pch = 1,
ylim = c(0, max(rad.n, rad.sn)),
xlab = "Percentiles of chi-square distribution",
ylab = "Mahalanobis distances"
)
abline(0, 1, lty = 2)
title(main = "QQ-plot for normal distribution", sub = y.name)
plot(
pp,
sort(rad.sn),
pch = 1,
ylim = c(0, max(rad.n, rad.sn)),
xlab = "Percentiles of chi-square distribution",
ylab = "Mahalanobis distances"
)
abline(0, 1, lty = 2)
title(main = "QQ-plot for skew-normal distribution", sub = y.name)
prob <- pchisq(rad.sn, k)
mle$mahalanobis <- list(distance = rad.sn,
prob = prob,
df = k)
cat("Press <Enter> to continue, 'q' to quit...")
m <- readline()
if (tolower(m) != "q") {
plot((1:n) / (n + 1),
sort(pchisq(rad.n, k)),
xlab = "",
ylab = "")
abline(0, 1, lty = 3)
title(main = "PP-plot for normal distribution", sub = y.name)
plot((1:n) / (n + 1),
sort(prob),
xlab = "",
ylab = "")
abline(0, 1, lty = 3)
title(main = "PP-plot for skew-normal distribution", sub = y.name)
}
par(mfrow = c(1, 1))
} # end ploting
dev.norm <- msn.dev(c(qr.coef(qrX, y), rep(0, k)), X, y, freq)
test <- dev.norm + 2 * mle$logL
p.value <- 1 - pchisq(test, k)
if (trace) {
cat("LRT for normality (test-function, p-value): ")
print(c(test, p.value))
}
mle$test.normality <- list(LRT = test, p.value = p.value)
invisible(mle)
}
msn.dev <- function(param, X, y, freq, trace = FALSE)
{
d <- ncol(y)
if (missing(freq))
freq <- rep(1, nrow(y))
n <- sum(freq)
m <- ncol(X)
beta <- matrix(param[1:(m * d)], m, d)
al.om <- param[(m * d + 1):(m * d + d)]
y0 <- y - X %*% beta
Omega <- (t(y0) %*% (y0 * freq)) / n
D <- diag(qr(2 * pi * Omega)[[1]])
logDet <- sum(log(abs(D)))
dev <- n * logDet - 2 * sum(zeta(0, y0 %*% al.om) * freq) + n * d
if (trace) {
cat("\nmsn.dev:", dev, "\n", "parameters:")
print(rbind(beta, al.om))
}
dev
}
msn.dev.grad <- function(param, X, y, freq, trace = FALSE) {
d <- ncol(y)
if (missing(freq))
freq <- rep(1, nrow(y))
n <- sum(freq)
m <- ncol(X)
beta <- matrix(param[1:(m * d)], m, d)
al.om <- param[(m * d + 1):(m * d + d)]
y0 <- y - X %*% beta
Omega <- (t(y0) %*% (freq * y0)) / n
p1 <- zeta(1, as.vector(y0 %*% al.om))
Dbeta <- t(X) %*% (y0 * freq) %*% solvePD(Omega) -
outer(as.vector(t(X * freq) %*% p1), al.om)
Dal.om <- as.vector(t(y0 * freq) %*% p1)
if (trace) {
cat("gradient:\n")
print(rbind(Dbeta, Dal.om))
}
- 2 * c(Dbeta, Dal.om)
}
num.deriv1 <- function(x, FUN, ...)
{
# calcola gradiente in modo numerico, se FUN calcola la funzione
FUN <- get(FUN, inherits = TRUE)
value <- FUN(x, ...)
p <- length(x)
grad <- numeric(p)
delta <- cbind((abs(x) + 1e-10) * 1e-5, rep(1e-06, p))
delta <- apply(delta, 1, max)
for (i in 1:p) {
x1 <- x
x1[i] <- x1[i] + delta[i]
grad[i] <- (FUN(x1, ...) - value) / delta[i]
}
grad
}
num.deriv2 <- function(x, FUN, ...)
{
# derivate seconde numeriche, se FUN calcola il gradiente
FUN <- get(FUN, inherits = TRUE)
values <- FUN(x, ...)
p <- length(values)
H <- matrix(0, p, p)
delta <- cbind((abs(x) + 1e-10) * 1e-5, rep(1e-06, p))
delta <- apply(delta, 1, max)
for (i in 1:p) {
x1 <- x
x1[i] <- x1[i] + delta[i]
H[, i] <- (FUN(x1, ...) - values) / delta[i]
}
(H + t(H)) / 2
}
dsn <- function(x,
location = 0,
scale = 1,
shape = 0,
dp = NULL,
log = FALSE)
{
if (!is.null(dp)) {
if (!missing(shape))
stop("You cannot set both component parameters and dp")
location <- dp[1]
scale <- dp[2]
shape <- dp[3]
}
z <- (x - location) / scale
if (log)
y <-
(-0.9189385332046727 - logb(scale) - z ^ 2 / 2 + zeta(0, shape * z))
else
y <- 2 * dnorm(z) * pnorm(z * shape) / scale
replace(y, scale <= 0, NaN)
}
psn <-
function(x,
location = 0,
scale = 1,
shape = 0,
dp = NULL,
engine,
...)
{
if (!is.null(dp)) {
if (!missing(shape))
stop("You cannot set both component parameters and dp")
location <- dp[1]
scale <- dp[2]
shape <- dp[3]
## h.mean <- if(length(dp)>3) dp[4] else 0
}
z <- as.numeric((x - location) / scale)
if (missing(engine))
engine <-
if (length(shape) == 1 &
length(x) > 3)
"T.Owen"
else
"biv.nt.prob"
if (engine == "T.Owen")
p <- pnorm(z) - 2 * T.Owen(z, shape, ...)
else {
zd <- cbind(z, shape / sqrt(1 + shape ^ 2))
np <- nrow(zd)
p <- numeric(np)
for (k in 1:np) {
R <- matrix(c(1, -zd[k, 2], -zd[k, 2], 1), 2, 2)
p[k] <-
2 * biv.nt.prob(0, rep(-Inf, 2), c(0, zd[k, 1]), rep(0, 2), R)
}
}
p <- pmin(1, pmax(0, p))
replace(p, scale <= 0, NaN)
}
rsn <- function(n = 1,
location = 0,
scale = 1,
shape = 0,
dp = NULL)
{
if (!is.null(dp)) {
if (!missing(shape))
stop("You cannot set both component parameters and dp")
location <- dp[1]
scale <- dp[2]
shape <- dp[3]
}
u1 <- rnorm(n)
u2 <- rnorm(n)
id <- (u2 > shape * u1)
u1[id] <- (-u1[id])
y <- location + scale * u1
attr(y, "parameters") <- c(location, scale, shape)
return(y)
}
qsn <- function (p,
location = 0,
scale = 1,
shape = 0,
dp = NULL,
tol = 1e-8,
engine,
...)
{
if (!is.null(dp)) {
if (!missing(shape))
stop("You cannot set both component parameters and dp")
location <- dp[1]
scale <- dp[2]
shape <- dp[3]
}
max.q <- sqrt(qchisq(p, 1))
min.q <- -sqrt(qchisq(1 - p, 1))
if (shape > 1e5)
return(location + scale * max.q)
if (shape < -1e5)
return(location + scale * min.q)
na <- is.na(p) | (p < 0) | (p > 1)
zero <- (p == 0)
one <- (p == 1)
p <- replace(p, (na | zero | one), 0.5)
cum <- sn.cumulants(0, 1, shape, n = 4)
g1 <- cum[3] / cum[2] ^ (3 / 2)
g2 <- cum[4] / cum[2] ^ 2
x <- qnorm(p)
x <- (x + (x ^ 2 - 1) * g1 / 6 + x * (x ^ 2 - 3) * g2 / 24 -
x * (2 * x ^ 2 - 5) * g1 ^ 2 / 36)
x <- cum[1] + sqrt(cum[2]) * x
if (missing(engine))
engine <-
if (length(shape) == 1 &
length(x) > 3)
"T.Owen"
else
"biv.nt.prob"
max.err <- 1
dp <- c(0, 1, shape)
while (max.err > tol) {
x1 <-
x - (psn(x, dp = dp, engine = engine, ...) - p) / dsn(x, dp = dp)
x1 <- pmin(x1, max.q)
x1 <- pmax(x1, min.q)
max.err <- max(abs(x1 - x) / (1 + abs(x)))
x <- x1
}
x <- replace(x, na, NA)
x <- replace(x, zero, -Inf)
x <- replace(x, one, Inf)
return(location + scale * x)
}
st.cumulants <-
function(location = 0,
scale = 1,
shape = 0,
df = Inf,
dp = NULL,
n = 4)
{
if (!is.null(dp)) {
if (!missing(shape))
stop("You cannot set both component parameters and dp")
location <- dp[1]
scale <- dp[2]
shape <- dp[3]
df <- dp[4]
}
if (df == Inf)
return(sn.cumulants(location, scale, shape, n = n))
n <- min(as.integer(n), 4)
if (df <= n)
stop("need df>n")
par <- cbind(location, scale, shape)
delta <- par[, 3] / sqrt(1 + par[, 3] ^ 2)
mu <-
delta * sqrt(df / pi) * exp(lgamma((df - 1) / 2) - lgamma(df /
2))
cum <- matrix(NA, nrow = nrow(par), ncol = n)
cum[, 1] <- mu
if (n > 1)
cum[, 2] <- df / (df - 2) - mu ^ 2
if (n > 2)
cum[, 3] <-
mu * (df * (3 - delta ^ 2) / (df - 3) - 3 * df / (df - 2) +
2 * mu ^ 2)
if (n > 3)
cum[, 4] <-
(3 * df ^ 2 / ((df - 2) * (df - 4)) - 4 * mu ^ 2 * df * (3 -
delta ^ 2) / (df - 3)
+ 6 * mu ^ 2 * df / (df - 2) - 3 * mu ^ 4) - 3 *
cum[, 2] ^ 2
cum <- cum * outer(par[, 2], 1:n, "^")
cum[, 1] <- cum[, 1] + par[, 1]
cum[, , drop = TRUE]
}
dmst <- function(x,
xi = rep(0, length(alpha)),
Omega,
alpha,
df = Inf,
dp = NULL,
log = FALSE)
{
if (!(missing(alpha) & missing(Omega)) && !is.null(dp))
stop("You cannot set both component parameters and dp")
if (!is.null(dp)) {
if (!is.null(dp$xi))
xi <- dp$xi
else
if (!is.null(dp$beta))
xi <- as.vector(dp$beta)
Omega <- dp$Omega
alpha <- dp$alpha
df <- dp$df
}
if (df == Inf)
return(dmsn(
x,
xi = xi,
Omega = Omega,
alpha = alpha,
log = log
))
d <- length(alpha)
Omega <- matrix(Omega, d, d)
x <- if (is.vector(x))
matrix(x, 1, d)
else
data.matrix(x)
if (is.vector(xi))
xi <- outer(rep(1, nrow(x)), xi)
X <- t(x - xi)
Q <- apply((solvePD(Omega) %*% X) * X, 2, sum)
L <- as.vector(t(X / sqrt(diag(Omega))) %*% as.matrix(alpha))
logDet <- sum(logb(abs(diag(qr(
Omega
)$qr))))
if (df < 10000) {
const <- lgamma((df + d) / 2) - lgamma(df / 2) - 0.5 * d * logb(df)
log1Q <- logb(1 + Q / df)
}
else {
const <- (-0.5 * d * logb(2) + log1p((d / 2) * (d / 2 - 1) / df))
log1Q <- log1p(Q / df)
}
log.dmt <-
const - 0.5 * (d * logb(pi) + logDet + (df + d) * log1Q)
log.pt <-
pt(L * sqrt((df + d) / (Q + df)), df = df + d, log.p = TRUE)
logPDF <- logb(2) + log.dmt + log.pt
if (log)
logPDF
else
exp(logPDF)
}
rmst <-
function(n = 1,
xi = rep(0, length(alpha)),
Omega,
alpha,
df = Inf,
dp = NULL)
{
if (!(missing(alpha) & missing(Omega)) && !is.null(dp))
stop("You cannot set both component parameters and dp")
if (!is.null(dp)) {
if (!is.null(dp$xi))
xi <- dp$xi
else
if (!is.null(dp$beta))
xi <- as.vector(dp$beta)
Omega <- dp$Omega
alpha <- dp$alpha
df <- dp$df
}
d <- length(alpha)
x <- if (df == Inf)
1
else
rchisq(n, df) / df
z <- rmsn(n, rep(0, d), Omega, alpha)
y <- t(xi + t(z / sqrt(x)))
attr(y, "parameters") <-
list(
xi = xi,
Omega = Omega,
alpha = alpha,
df = df
)
return(y)
}
pmst <- function(x,
xi = rep(0, length(alpha)),
Omega,
alpha,
df = Inf,
dp = NULL,
...)
{
if (!(missing(alpha) & missing(Omega)) && !is.null(dp))
stop("You cannot set both component parameters and dp")
if (!is.null(dp)) {
if (!is.null(dp$xi))
xi <- dp$xi
else
if (!is.null(dp$beta))
xi <- as.vector(dp$beta)
Omega <- dp$Omega
alpha <- dp$alpha
df <- dp$df
}
d <- length(alpha)
Omega <- matrix(Omega, d, d)
omega <- sqrt(diag(Omega))
Ocor <- cov2cor(Omega)
O.alpha <- as.vector(Ocor %*% alpha)
delta <- O.alpha / sqrt(1 + sum(alpha * O.alpha))
Obig <-
matrix(rbind(c(1,-delta), cbind(-delta, Ocor)), d + 1, d +
1)
x <- c(0, (x - xi) / omega)
if (df > .Machine$integer.max)
2 * pmnorm(x, mean = rep(0, d + 1), varcov = Obig, ...)
else
2 * pmt(x,
mean = rep(0, d + 1),
S = Obig,
df = df,
...)
}
dst2.plot <- function(x, y, xi, Omega, alpha, df, dp = NULL, ...)
{
# plot bivariate density ST_2(xi,Omega,alpha,df) computed at (x,y) grid
if (!(missing(alpha) & missing(Omega)) && !is.null(dp))
stop("You cannot set both component parameters and dp")
if (!is.null(dp)) {
if (!is.null(dp$xi))
xi <- dp$xi
else
if (!is.null(dp$beta))
xi <- as.vector(dp$beta)
Omega <- dp$Omega
alpha <- dp$alpha
df <- dp$df
}
if (any(dim(Omega) != c(2, 2)))
stop("dim(Omega) != c(2,2)")
nx <- length(x)
ny <- length(y)
xoy <-
cbind(rep(x, ny), as.vector(matrix(y, nx, ny, byrow = TRUE)))
X <- matrix(xoy, nx * ny, 2, byrow = FALSE)
pdf <- dmst(X, xi, Omega, alpha, df)
pdf <- matrix(pdf, nx, ny)
contour(x, y, pdf, ...)
invisible(list(
x = x,
y = y,
density = pdf,
xi = xi,
Omega = Omega,
alpha = alpha,
df = df
))
}
mst.fit <- function(X,
y,
freq,
start,
fixed.df = NA,
plot.it = TRUE,
trace = FALSE,
...)
{
y.name <- deparse(substitute(y))
y.names <- dimnames(y)[[2]]
y <- as.matrix(y)
d <- ncol(y)
if (is.null(d))
d <- 1
if (d > 1) {
if (length(y.names) == 0) {
dimnames(y) <-
list(dimnames(y)[[1]], outer("V", as.character(1:d), paste, sep =
""))
y.names <- as.vector(dimnames(y)[[2]])
}
}
else
colnames(y) <- y.name
if (missing(freq))
freq <- rep(1, nrow(y))
n <- sum(freq)
if (missing(X)) {
X <- rep(1, nrow(y))
missing.X <- TRUE
}
else
missing.X <- FALSE
X <- as.matrix(X)
qrX <- qr(X)
m <- ncol(X)
mle <-
mst.mle(
X = X,
y = y,
freq = freq,
fixed.df = fixed.df,
start = start,
trace = trace,
...
)
mle$call <- match.call()
beta <- mle$dp$beta
Omega <- mle$dp$Omega
alpha <- mle$dp$alpha
omega <- sqrt(diag(Omega))
df <- mle$dp$df
xi <- X %*% beta
if (plot.it & all(freq == rep(1, length(y)))) {
if (missing.X) {
y0 <- y
xi0 <- apply(xi, 2, mean)
}
else {
y0 <- y - xi
xi0 <- rep(0, d)
}
if (d > 1) {
opt <- options()
options(warn = -1)
pairs(
y0,
labels = y.names,
panel = function(x, y, Y, y.names, xi, Omega, alpha)
{
for (i in 1:length(alpha)) {
if (all(Y[, i] == x))
Ix <- i
if (all(Y[, i] == y))
Iy <- i
}
points(x, y)
marg <-
msn.marginal(xi, Omega , alpha, c(Ix, Iy))
xi.marg <- marg$xi
Omega.marg <- marg$Omega
alpha.marg <- marg$alpha
x1 <- seq(min(x), max(x), length = 30)
x2 <- seq(min(y), max(y), length = 30)
dst2.plot(x1,
x2,
xi.marg,
Omega.marg,
alpha.marg,
df,
add = TRUE,
col = 2)
},
# end "panel" function
Y = y0,
y.names = y.names,
xi = xi0,
Omega = Omega,
alpha = alpha
)
options(opt)
}
else{
# plot for case d=1
y0 <- as.vector(y0)
x <- seq(min(pretty(y0, 10)), max(pretty(y0, 10)), length =
100)
if (missing.X) {
dp0 <- c(xi0, omega, alpha, df)
xlab <- y.name
}
else {
dp0 <- c(0, omega, alpha, df)
xlab <- "residuals"
}
hist(
y0,
prob = TRUE,
breaks = "FD",
xlab = xlab,
ylab = "density",
main = ""
)
lines(x, dst(x, dp0[1], dp0[2], dp0[3], dp0[4]), col = 2)
if (length(y) < 101)
points(y0, rep(0, n), pch = 1)
title(y.name)
}
cat("Press <Enter> to continue...")
readline()
par(mfrow = c(1, 2))
pp <- d * qf((1:n) / (n + 1), d, df)
pp2 <- qchisq((1:n) / (n + 1), d)
## Xb <- qr.fitted(qrX,y)
res <- qr.resid(qrX, y)
rad.n <-
apply(res * (res %*% solvePD(var(res))), 1, sum)
rad.st <-
apply((y - xi) * ((y - xi) %*% solvePD(Omega)), 1, sum)
plot(
pp2,
sort(rad.n),
pch = 1,
ylim = c(0, max(rad.n, rad.st)),
xlab = "Percentiles of chi-square distribution",
ylab = "Mahalanobis distances"
)
abline(0, 1, lty = 3)
title(main = "QQ-plot for normal distribution", sub = y.name)
plot(
pp,
sort(rad.st),
pch = 1,
ylim = c(0, max(rad.n, rad.st)),
xlab = "Percentiles of scaled F distribution",
ylab = "Mahalanobis distances"
)
abline(0, 1, lty = 3)
title(main = "QQ-plot for skew-t distribution", sub = y.name)
prob <- pf(rad.st / d, d, df)
mle$mahalanobis <-
list(distance = rad.st,
prob = prob,
df = c(d, df))
cat("Press <Enter> to continue, 'q' to quit...")
m <- readline()
if (tolower(m) != "q") {
plot((1:n) / (n + 1),
sort(pchisq(rad.n, d)),
xlab = "",
ylab = "")
abline(0, 1, lty = 3)
title(main = "PP-plot for normal distribution", sub = y.name)
plot((1:n) / (n + 1),
sort(prob),
xlab = "",
ylab = "")
abline(0, 1, lty = 3)
title(main = "PP-plot for skew-t distribution", sub = y.name)
}
par(mfrow = c(1, 1))
} # end ploting
dev.norm <-
msn.dev(c(qr.coef(qrX, y), rep(0, d)), as.matrix(X), y, freq)
test <- dev.norm + 2 * mle$logL
p.value <- 1 - pchisq(test, d + 1)
if (trace) {
cat("LRT for normality (test-function, p-value): ")
print(c(test, p.value))
}
mle$test.normality <- list(
LRT = test,
df = d + 1,
p.value = p.value,
normal.logL = dev.norm / (-2)
)
invisible(mle)
}
mst.dev <-
function(param,
X,
y,
freq = rep(1, nrow(X)),
fixed.df = NA,
trace = FALSE)
{
## Diag <- function(x) diag(x, nrow=length(x), ncol=length(x))
d <- ncol(y)
## if(missing(freq)) freq<-rep(1,nrow(y))
n <- sum(freq)
m <- ncol(X)
beta <- matrix(param[1:(m * d)], m, d)
D <- exp(-2 * param[(m * d + 1):(m * d + d)])
i0 <- m * d + d * (d + 1) / 2
A <- diag(d)
if (d > 1)
A[!lower.tri(A, diag = TRUE)] <- param[(m * d + d + 1):i0]
eta <- param[(i0 + 1):(i0 + d)]
if (is.na(fixed.df))
df <- exp(param[i0 + d + 1])
else
df <- fixed.df
Oinv <- t(A) %*% diag(D, d, d) %*% A
## Omega <- solvePD(Oinv)
u <- y - X %*% beta
Q <- apply((u %*% Oinv) * u, 1, sum)
L <- as.vector(u %*% eta)
logDet <- sum(-log(D))
if (df < 10000) {
const <- lgamma((df + d) / 2) - lgamma(df / 2) - 0.5 * d * logb(df)
DQ <- (df + d) * sum(freq * logb(1 + Q / df))
L. <- L * sqrt((df + d) / (Q + df))
}
else {
const <- (-0.5 * d * logb(2) + log1p((d / 2) * (d / 2 - 1) / df))
DQ <-
if (df < Inf)
(df + d) * sum(freq * log1p(Q / df))
else
sum(freq * Q)
L. <- L * sqrt((1 + d / df) / (1 + Q / df))
}
dev <- (n * (logDet - 2 * const + d * logb(pi)) + DQ
- 2 * sum(freq * (log(2) + log.pt(L., df + d))))
if (trace)
cat("mst.dev: ", dev, "\n")
dev
}
mst.dev.grad <-
function(param,
X,
y,
freq = rep(1, nrow(X)),
fixed.df = NA,
trace = FALSE)
{
## Diag <- function(x) diag(x, nrow=length(x), ncol=length(x))
d <- ncol(y)
n <- sum(freq)
m <- ncol(X)
beta <- matrix(param[1:(m * d)], m, d)
D <- exp(-2 * param[(m * d + 1):(m * d + d)])
A <- diag(d)
i0 <- m * d + d * (d + 1) / 2
if (d > 1)
A[!lower.tri(A, diag = TRUE)] <- param[(m * d + d + 1):i0]
eta <- param[(i0 + 1):(i0 + d)]
if (is.na(fixed.df))
df <- exp(param[i0 + d + 1])
else
df <- fixed.df
Oinv <- t(A) %*% diag(D, d, d) %*% A
u <- y - X %*% beta
Q <- as.vector(apply((u %*% Oinv) * u, 1, sum))
L <- as.vector(u %*% eta)
sf <-
if (df < 10000)
sqrt((df + d) / (Q + df))
else
sqrt((1 + d / df) / (1 + Q / df))
t. <- L * sf
dlogft <- (-0.5) * (1 + d / df) / (1 + Q / df)
dt.dL <- sf
dt.dQ <- (-0.5) * L * sf / (Q + df)
logT. <- log.pt(t., df + d)
dlogT. <- exp(dt(t., df + d, log = TRUE) - logT.)
u.freq <- u * freq
Dbeta <- (
-2 * t(X) %*% (u.freq * dlogft) %*% Oinv
- outer(as.vector(t(X) %*% (
dlogT. * dt.dL * freq
)), eta)
- 2 * t(X) %*% (dlogT. * dt.dQ * u.freq) %*% Oinv
)
Deta <- apply(dlogT. * sf * u.freq, 2, sum)
if (d > 1) {
M <- 2 * (diag(D, d, d) %*% A %*% t(u * dlogft
+ u * dlogT. * dt.dQ) %*% u.freq)
DA <- M[!lower.tri(M, diag = TRUE)]
}
else
DA <- NULL
M <-
(A %*% t(u * dlogft + u * dlogT. * dt.dQ) %*% u.freq %*% t(A))
if (d > 1)
DD <- diag(M) + 0.5 * n / D
else
DD <- as.vector(M + 0.5 * n / D)
grad <- (-2) * c(Dbeta, DD * (-2 * D), DA, Deta)
if (is.na(fixed.df)) {
df0 <- if (df < Inf)
df
else
1e8
if (df0 < 10000) {
diff.digamma <- digamma((df0 + d) / 2) - digamma(df0 / 2)
log1Q <- log(1 + Q / df0)
}
else
{
diff.digamma <- log1p(d / df0)
log1Q <- log1p(Q / df0)
}
dlogft.ddf <- 0.5 * (diff.digamma - d / df0
+ (1 + d / df0) * Q / ((1 + Q / df0) * df0) - log1Q)
eps <- 1.0e-4
df1 <- df0 + eps
sf1 <-
if (df0 < 10000)
sqrt((df1 + d) / (Q + df1))
else
sqrt((1 + d / df1) / (1 + Q / df1))
logT.eps <- log.pt(L * sf1, df1 + d)
dlogT.ddf <- (logT.eps - logT.) / eps
Ddf <- sum((dlogft.ddf + dlogT.ddf) * freq)
grad <- c(grad, -2 * Ddf * df0)
}
if (trace)
cat("mst.dev.grad: norm is ", sqrt(sum(grad ^ 2)), "\n")
return(grad)
}
##-------------
st.2logL.profile <- function(X = matrix(rep(1, n)),
y,
freq,
trace = FALSE,
fixed.comp = c(ncol(X) + 2, ncol(X) + 3),
fixed.values = cbind(c(-4, 4), log(c(1, 25))),
npts = 51 / length(fixed.comp),
plot.it = TRUE,
...)
{
## plot2D profile deviance (=2(max.logL-logL)) using either parameters
## if(plot.it & !exists(.Device)) stop("Device not active")
##
if (missing(freq))
freq <- rep(1, length(y))
n <- sum(freq)
m <- ncol(X)
npts <- as.integer(npts)
if (length(fixed.comp) == 1) {
param1 <- seq(fixed.values[1], fixed.values[2], length = npts)
logL <- param2 <- rep(NA, npts)
}
else{
param1 <- seq(fixed.values[1, 1], fixed.values[2, 1], length = npts)
param2 <-
seq(fixed.values[1, 2], fixed.values[2, 2], length = npts)
logL <- matrix(NA, npts, npts)
}
ls <- lm.fit(X, y)
omega <- sqrt(var(resid(ls)))
param <- c(coef(ls), log(omega), 0, log(20))[-fixed.comp]
max.logL <- (-Inf)
if (trace)
cat(c("Running up to", npts, ":"))
for (i in 1:npts) {
if (trace)
cat(" ", i)
if (length(fixed.comp) == 1) {
opt <- optim(
param,
fn = st.dev.fixed,
method = "Nelder-Mead",
X = X,
y = y,
freq = freq,
trace = trace,
fixed.comp = fixed.comp,
fixed.values = param1[i]
)
logL[i] <- opt$value / (-2)
param <- opt$par
if (logL[i] > max.logL) {
max.logL <- logL[i]
param <- numeric(m + 3)
param[fixed.comp] <- param1[i]
param[-fixed.comp] <- opt$par
dp <-
c(param[1:m], exp(param[m + 1]), param[m + 2], exp(param[m + 3]))
best <- list(
fixed.comp1 = param1[i],
fixed.comp2 = NA,
dp = dp,
logL = max.logL,
opt = opt
)
param <- param[-fixed.comp]
}
}
else{
for (j in 1:npts) {
opt <- optim(
param,
fn = st.dev.fixed,
method = "Nelder-Mead",
X = X,
y = y,
freq = freq,
trace = trace,
fixed.comp = fixed.comp,
fixed.values = c(param1[i], param2[j])
)
logL[i, j] <- opt$value / (-2)
if (j == 1)
param0 <- opt$par
if (j < npts)
param <- opt$par
else
param <- param0
if (logL[i, j] > max.logL) {
max.logL <- logL[i, j]
param <- numeric(m + 3)
param[fixed.comp] <- c(param1[i], param2[j])
param[-fixed.comp] <- opt$par
dp <-
c(param[1:m], exp(param[m + 1]), param[m + 2], exp(param[m + 3]))
best <-
list(
fixed.comp1 = param1[i],
fixed.comp2 = param2[j],
dp = dp,
logL = max.logL,
opt = opt
)
param <- param[-fixed.comp]
}
}
}
}
if (trace)
cat("\n")
dev <- 2 * (max(logL) - logL)
if (plot.it) {
if (length(fixed.comp) == 1) {
plot(param1, dev, type = "l", ...)
points(x = best$fixed.comp1,
y = 0,
pch = 1)
}
else{
contour(
param1,
param2,
dev,
labcex = 0.5,
levels = c(0.57, 1.37, 2.77, 4.6, 5.99, 9.2),
labels = c(0.25, 0.5, 0.75, 0.90, 0.95, 0.99),
...
)
points(
x = best$fixed.comp1,
y = best$fixed.comp2,
pch = 1,
cex = 0.5
)
}
}
title(main = paste("Dataset:", deparse(substitute(y)),
"\nProfile deviance", sep = " "))
invisible(
list(
call = match.call(),
param1 = param1,
param2 = param2,
deviance = dev,
max.logL = max.logL,
best = best
)
)
}
st.dev.fixed <- function(free.param,
X,
y,
freq,
trace = FALSE,
fixed.comp = NA,
fixed.values = NA)
{
## param components: beta, log(omega), alpha, log(df)
n <- sum(freq)
m <- ncol(X)
param <- numeric(length(free.param) + length(fixed.comp))
param[fixed.comp] <- fixed.values
param[-fixed.comp] <- free.param
beta <- param[1:m]
omega <- exp(param[m + 1])
eta <- param[m + 2] / omega
df <- exp(param[m + 3])
u <- y - X %*% beta
Q <- freq * (u / omega) ^ 2
L <- u * eta
logDet <- 2 * log(omega)
if (df < 10000) {
const <- lgamma((df + 1) / 2) - lgamma(df / 2) - 0.5 * logb(df)
log1Q <- logb(1 + Q / df)
}
else {
const <- (-0.5 * logb(2) + log1p((1 / 2) * (-1 / 2) / df))
log1Q <- log1p(Q / df)
}
dev <-
(n * (logDet - 2 * const + logb(pi)) + (df + 1) * sum(freq * log1Q)
- 2 * sum(log(2) + log.pt(L * sqrt((
df + 1
) / (
Q + df
)), df + 1)))
if (trace)
cat("st.dev.fixed (param, dev): ", param, dev, "\n")
dev
}
##----
sn.SFscore <- function(delta,
X,
y,
exact = FALSE,
trace = FALSE)
{
## Sartori-Firth's modified score function, with Bayes-Branco approx
shape <- delta / sqrt(1 - delta ^ 2)
dp <- sn.em(X, y, fixed = c(NA, NA, shape), trace = FALSE)$dp
z <- (y - X %*% dp[1:ncol(X)]) / dp[ncol(X) + 1]
if (exact) {
funct <- function(x, alpha, k = 0)
dsn(x, 0, 1, alpha) * x ^ k * zeta(1, alpha * x) ^ 2
a2 <- integrate(funct, -Inf, Inf, alpha = shape, k = 2)$value
a4 <- integrate(funct, -Inf, Inf, alpha = shape, k = 4)$value
M <- (-0.5) * shape * a4 / a2
} else
M <- (-3 / 2) * shape / (1 + 8 * (shape / pi) ^ 2)
score <- sum(zeta(1, shape * z) * z) + M
if (trace)
cat("sn.SFscore: (shape,score)=", format(c(shape, score)), "\n")
attr(score, "dp") <- dp
score
}
sn.mmle <-
function(X,
y,
plot.it = TRUE,
exact = FALSE,
trace = FALSE,
...)
{
## Sartori-Firth method; function revised in 2011
n <- length(y)
if (missing(X)) {
X <- as.matrix(rep(1, n))
colnames(X) <- "constant"
}
p <- ncol(X)
dp <-
cp.to.dp(sn.mle(
X = X,
y = y,
plot.it = plot.it,
trace = trace,
...
)$cp)
sk <- dp[length(dp)]
d0 <- sign(-sk) * 0.01
d1 <- sign(sk) * 0.99999
a <-
uniroot(
sn.SFscore,
c(d0, d1),
X = X,
y = y,
exact = exact,
trace = trace
)
score <- sn.SFscore(a$root, X, y, exact = exact)
dp <- attr(score, "dp")
names(dp)[p + 2] <- "shape"
logL <-
sum(dsn(y, as.vector(X %*% dp[1:p]), dp[p + 1], dp[p + 2], log = TRUE))
if (trace)
cat("Modified MLE: ", dp, ", logL: ", logL, "\n")
if (plot.it) {
dp0 <- dp
if (all(X == rep(1, n)))
y0 <- y
else {
y0 <- y - as.vector(X %*% dp0[1:p])
dp0 <- c(0, dp0[p + 1], dp0[p + 2])
xlab <- "residuals"
}
x <-
seq(min(pretty(y0, 10)), max(pretty(y0, 10)), length = 200)
curve(dsn(x, dp = dp0),
add = TRUE,
lty = 2,
col = 3)
}
info <- sn.Einfo(dp = dp, x = X)
list(
call = match.call(),
dp = dp,
se = info$se.dp,
Einfo = info$info.dp
)
}
st.SFscore <- function(shape, df, z, trace = FALSE)
{
## Sartori-Firth's modified score function for skew-t case
U <- function(x, shape, df) {
u <- x * sqrt((df + 1) / (x ^ 2 + df))
u * dt(shape * u, df = df + 1) / pt(shape * u, df = df + 1)
}
J <- function(x, shape, df) {
u <- x * sqrt((df + 1) / (x ^ 2 + df))
tee <- dt(shape * u, df = df + 1)
Tee <- pt(shape * u, df = df + 1)
((df + 1) * shape * u ^ 3 * tee / ((df + 2) * (1 + (shape * u) ^
2 / (df + 1))) + (tee * u / Tee) ^ 2)
}
EJ <- integrate(
function(x, shape = shape, df = df)
J(x, shape = shape, df = df) * dst(x, 0, 1, shape, df),
-Inf,
Inf,
shape = shape,
df = df
)$value
nu111 <- integrate(
function(x, shape = shape, df = df)
U(x, shape = shape, df = df) ^ 3 * dst(x, 0, 1, shape, df),
-Inf,
Inf,
shape = shape,
df = df
)$value
nu1.2 <- integrate(
function(x, shape = shape, df = df)
U(x, shape = shape, df = df) * J(x, shape = shape, df =
df) *
dst(x, 0, 1, shape, df),-Inf,
Inf,
shape = shape,
df = df
)$value
M <- 0.5 * (nu111 + nu1.2) / EJ
u <- z * sqrt((df + 1) / (z ^ 2 + df))
score <-
sum(u * dt(shape * u, df = df + 1) / pt(shape * u, df = df +
1)) + M
if (trace)
cat("st.SFscore(shape,score):", shape, score, "\n")
score
}
sn.Einfo <- function(dp = NULL,
cp = NULL,
n = 1,
x = NULL)
{
## computes Expected Fisher information matrix for SN variates
if (is.null(dp) &
is.null(cp))
stop("either dp or cp must be set")
if (!is.null(dp) &
!is.null(cp))
stop("either dp or cp must be set")
if (is.null(cp))
cp <- dp.to.cp(dp)
if (is.null(dp))
dp <- cp.to.dp(cp)
if (is.null(x))
{
x <- matrix(rep(1, n), nrow = n, ncol = 1)
xx <- n
sum.x <- n
p <- 1
}
else
{
if (n != 1)
warning("You have set both n and x, I am setting n<-nrow(x)")
n <- nrow(x)
p <- ncol(x)
xx <- t(x) %*% x
sum.x <- matrix(apply(x, 2, sum))
}
if (length(cp) != (p + 2) | length(dp) != (p + 2))
stop("length(dp) | length(cp) must be equal to ncol(x)+2")
omega <- dp[p + 1]
alpha <- dp[p + 2]
E.z <- sqrt(2 / pi) * alpha / sqrt(1 + alpha ^ 2)
s.z <- sqrt(1 - E.z ^ 2)
I.dp <- matrix(NA, p + 2, p + 2)
if (abs(alpha) < 200) {
a0 <- integrate(function(x)
dsn(x, 0, 1, alpha) * zeta(1, alpha * x) ^ 2, -Inf, Inf)$value
a1 <-
integrate(function(x)
dsn(x, 0, 1, alpha) * x * zeta(1, alpha * x) ^ 2, -Inf, Inf)$value
a2 <-
integrate(function(x)
dsn(x, 0, 1, alpha) * x ^ 2 * zeta(1, alpha * x) ^ 2,
-Inf,
Inf)$value
}
else
{
a0 <- sign(alpha) * 0.7206 / abs(alpha)
a1 <- -sign(alpha) * (0.6797 / alpha) ^ 2
a2 <-
2 * pi ^ 2 / (pi ^ 2 + 8 * alpha ^ 2) ^ 1.5 # Bayes&Branco, (2.3)
}
I.dp[1:p, 1:p] <- xx * (1 + alpha ^ 2 * a0) / omega ^ 2
I.dp[p + 1, p + 1] <- n * (2 + alpha ^ 2 * a2) / omega ^ 2
I.dp[p + 2, p + 2] <- n * a2
I.dp[1:p, p + 1] <-
sum.x * (E.z * (1 + E.z ^ 2 * pi / 2) + alpha ^ 2 * a1) / omega ^ 2
I.dp[p + 1, 1:p] <- t(I.dp[1:p, p + 1])
I.dp[1:p, p + 2] <-
sum.x * (sqrt(2 / pi) / (1 + alpha ^ 2) ^ 1.5 - alpha * a1) / omega
I.dp[p + 2, 1:p] <- t(I.dp[1:p, p + 2])
I.dp[p + 1, p + 2] <-
I.dp[p + 2, p + 1] <- n * (-alpha * a2) / omega
## cp <- dp.to.cp(dp)
sigma <- cp[p + 1]
gamma1 <- cp[p + 2]
D <- diag(p + 2)
R <- E.z / s.z
Tee <- sqrt(2 / pi - (1 - 2 / pi) * R ^ 2)
Da.Dg <-
2 * (Tee / (Tee * R) ^ 2 + (1 - 2 / pi) / Tee ^ 3) / (3 * (4 -
pi))
DE.z <- sqrt(2 / pi) / (1 + alpha ^ 2) ^ 1.5
Ds.z <- (-E.z / s.z) * DE.z
D[1, p + 1] <- (-R)
D[1, p + 2] <- (-sigma * R) / (3 * gamma1)
D[p + 1, p + 1] <- 1 / s.z
D[p + 1, p + 2] <- (-sigma) * Ds.z * Da.Dg / s.z ^ 2
D[p + 2, p + 2] <- Da.Dg
I.cp <- t(D) %*% I.dp %*% D
I.cp <- (I.cp + t(I.cp)) / 2
se.dp <- sqrt(diag(solvePD(I.dp)))
se.cp <- sqrt(diag(solvePD(I.cp)))
dimnames(I.cp) <- list(names(cp), names(cp))
dimnames(I.dp) <- list(names(dp), names(dp))
aux <- list(Deriv = D, a.int = c(a0, a1, a2))
list(
dp = dp,
cp = cp,
info.dp = I.dp,
info.cp = I.cp,
se.dp = se.dp,
se.cp = se.cp,
aux = aux
)
}
##----
sn.logL.grouped <- function(param, breaks, freq, trace = FALSE)
{
cdf <- pmax(psn(breaks, param[1], exp(param[2]), param[3]), 0)
p <- diff(cdf)
logL <- sum(freq * log(p))
if (trace)
print(c(param, logL))
logL
}
sn.mle.grouped <- function(breaks,
freq,
trace = FALSE,
start = NA)
{
if (any(is.na(start))) {
b <- breaks
d <- diff(b)
if (b[1] == -Inf)
b[1] <- b[2] - d[2]
if (b[length(b)] == Inf)
b[length(b)] <- b[length(b) - 1] + d[length(d) - 1]
mid <- (b[-1] + b[-length(b)]) / 2
dp <- msn.mle(y = mid,
freq = freq,
trace = trace)$dp
start <- c(dp[[1]], log(sqrt(dp[[2]])), dp[[3]])
}
opt <- optim(
start,
sn.logL.grouped,
control = list(fnscale = -1),
breaks = breaks,
freq = freq,
trace = trace
)
param <- opt$par
dp <- c(param[1], exp(param[2]), param[3])
invisible(list(
call = match.call(),
dp = dp,
logL = opt$value,
end = param,
opt = opt
))
}
st.logL.grouped <- function(param, breaks, freq, trace = FALSE)
{
if (param[4] > 5.5214609)
## 5.5214609=log(250)
cdf <- psn(breaks, param[1], exp(param[2]), param[3])
else
cdf <-
pst(breaks, param[1], exp(param[2]), param[3], exp(param[4]))
p <- pmax(diff(cdf), 1.0e-10)
logL <- sum(freq * log(p))
if (trace)
print(c(param, logL))
logL
}
st.mle.grouped <- function(breaks,
freq,
trace = FALSE,
start = NA)
{
if (any(is.na(start))) {
a <- sn.mle.grouped(breaks, freq)
start <- c(a$end, log(15))
if (trace)
cat("Initial parameters set to:", format(start), "\n")
}
opt <- optim(
start,
st.logL.grouped,
control = list(fnscale = -1),
breaks = breaks,
freq = freq,
trace = trace
)
param <- opt$par
dp <- c(param[1], exp(param[2]), param[3], exp(param[4]))
logL <- opt$value
invisible(list(
call = match.call(),
dp = dp,
logL = logL,
end = param,
opt = opt
))
}
msn.affine <- function(dp, a = 0, A, drop = TRUE)
{
## computes distribution of affine transformation of MSN/MST variate, T=a+AY,
## using formulae in Appendix A.2 of Capitanio et al.(2003)
##
Diag <- function(x)
diag(x, nrow = length(x), ncol = length(x))
if (is.null(dp$xi))
xi <- dp$beta
else
xi <- dp$xi
xi.T <- as.vector(A %*% matrix(xi, ncol = 1) + a)
Omega <- dp$Omega
O.T <- as.matrix(A %*% Omega %*% t(A))
oi <- Diag(1 / sqrt(diag(Omega)))
B <- oi %*% Omega %*% t(A)
tmp <-
(oi %*% Omega %*% oi - B %*% solvePD(O.T) %*% t(B)) %*% dp$alpha
den <- sqrt(1 + sum(dp$alpha * as.vector(tmp)))
num <-
Diag(sqrt(diag(O.T))) %*% solvePD(O.T) %*% t(B) %*% dp$alpha
alpha <- as.vector(num / den)
if (all(dim(O.T) == c(1, 1)) & drop)
dp.T <-
list(location = xi.T,
scale = sqrt(as.vector(O.T)),
shape = alpha)
else
dp.T <- list(xi = xi.T,
Omega = O.T,
alpha = alpha)
if (!is.null(dp$tau))
dp.T$tau <- dp$tau
if (!is.null(dp$df))
dp.T$df <- dp$df
return(dp.T)
}
mst.affine <-
function(dp, a = 0, A, drop = TRUE)
msn.affine(dp, a, A, drop)
##---
st.cumulants.inversion <- function(cum, abstol = 1e-8)
{
st.cumulants.matching <- function(par, gamma)
{
cum <- st.cumulants(shape = par[1],
df = exp(par[2]) + 4,
n = 4)
g1 <- cum[3] / cum[2] ^ 1.5
g2 <- cum[4] / cum[2] ^ 2
(abs(g1 - gamma[1]) ^ 1.5 / (1 + abs(gamma[1])) +
abs(g2 - gamma[2]) ^ 1.5 / (1 + gamma[2]))
}
if (length(cum) != 4)
stop("cum must be a vector of length 4")
g1 <- cum[3] / cum[2] ^ 1.5
g2 <- cum[4] / cum[2] ^ 2
## if(g2<0) {
## warning("cumulants matching may be inaccurate")
## return(c(location=cum[1], scale=sqrt(cum[2]), shape=0, df=Inf))
## }
opt1 <- optim(
c(0, 1),
st.cumulants.matching,
control = list(abstol = abstol),
gamma = c(g1, g2)
)
opt2 <- nlminb(
c(0, 1),
st.cumulants.matching,
control = list(abs.tol = abstol),
gamma = c(g1, g2)
)
if (opt1$value < opt2$objective)
par <- opt1$par
else
par <- opt2$par
if (min(opt1$value, opt2$objective) > abstol)
warning("cumulants matching may be inaccurate")
alpha <- par[1]
df <- exp(par[2]) + 4
cumZ <- st.cumulants(dp = c(0, 1, alpha, df))
omega <- sqrt(cum[2] / cumZ[2])
c(
location = cum[1] - omega * cumZ[1],
scale = omega,
shape = alpha,
df = df
)
}
sample.centralmoments <- function(x,
w = rep(1, length(x)),
order = 4)
{
## central moments, but first term is ordinary mean
if (order < 1 | order != round(order))
stop("order must be a positive integer")
x <- as.vector(x)
m <- weighted.mean(x, w = w, na.rm = TRUE)
mom <- rep(0, order)
mom[1] <- m
if (order > 1)
for (k in 2:order)
mom[k] <- weighted.mean((x - m) ^ k, w = w, na.rm = TRUE)
mom
}
solvePD <- function(x)
{
## inverse of a symmetric positive definite matrix
u <- chol(x, pivot = FALSE)
if (prod(diag(u)) <= 0)
stop("matrix not positive definite")
## ui <- backsolve(u,diag(ncol(x)))
## ui %*% t(ui)
chol2inv(u)
}
##---
log.pt <- function(x, df) {
## fix for log(pt(...)) when it gives -Inf
## see Abramowitz & Stegun formulae 26.7.8 & 26.2.13)
## However, new releases of R (>=2.3) seem to have fixed the problem
if (df == Inf)
return(pnorm(x, log.p = TRUE))
p <- pt(x, df = df, log.p = TRUE)
ninf <- (p == -Inf)
x0 <-
(1 - 1 / (4 * df)) * (-x[ninf]) / sqrt(1 + x[ninf] ^ 2 / (2 *
df))
p[ninf] <-
dnorm(x0, log = TRUE) - log(x0) + log1p(-1 / (x0 ^ 2 + 2))
p
}
st.mmle <- function(X, y, df, trace = FALSE)
{
n <- length(y)
if (missing(X)) {
X <- as.matrix(rep(1, n))
colnames(X) <- "constant"
}
m <- ncol(X)
dp <- st.mle(
X = X,
y = y,
fixed.df = df,
trace = trace
)$dp
z <- (y - as.vector(X %*% dp[1:m])) / dp[m + 1]
start <- sign(dp[m + 2]) * min(5000, abs(dp[m + 2]))
a0 <- start / 4
f0 <- st.SFscore(a0, df, z, trace = trace)
a1 <- start
f1 <- st.SFscore(a1, df, z, trace = trace)
while (f0 * f1 > 0) {
a1 <- a0
f1 <- f0
a0 <- a0 / 4
f0 <- st.SFscore(a0, df, z, trace = trace)
}
if (trace)
cat("st.mmle: (a0, a1)= ", a0, a1, "\n")
a <-
uniroot(
st.SFscore,
interval = c(a0, a1),
df = df,
z = z,
trace = trace
)
dp <- c(dp[1:(m + 1)], shape = a$root, df = df)
list(call = match.call(), dp = dp)
}
.checkSameEsets <- function(esets) {
matrix.one <- exprs(esets[[1]])
dimnames(matrix.one) <- NULL
matrix.two <- exprs(esets[[2]])
dimnames(matrix.two) <- NULL
pdata.one <- pData(esets[[1]])
rownames(pdata.one) <- NULL
pdata.two <- pData(esets[[2]])
rownames(pdata.two) <- NULL
output <-
identical(matrix.one, matrix.two) &
identical(pdata.one, pdata.two)
return(output)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.