Nothing
#
# fields is a package for analysis of spatial data written for
# the R software environment.
# Copyright (C) 2024 Colorado School of Mines
# 1500 Illinois St., Golden, CO 80401
# Contact: Douglas Nychka, douglasnychka@gmail.com,
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with the R software environment if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# or see http://www.r-project.org/Licenses/GPL-2
##END HEADER
"Krig" <- function(x, Y, cov.function = "stationary.cov",
lambda = NA, df = NA, GCV = FALSE, Z = NULL, cost = 1,
weights = NULL, m = 2, nstep.cv = 200, scale.type = "user",
x.center = rep(0, ncol(x)), x.scale = rep(1, ncol(x)), sigma = NA,
tau2 = NA, method = "REML", verbose = FALSE,
null.function = "Krig.null.function", wght.function = NULL,
offset = 0, na.rm = TRUE, cov.args = NULL,
chol.args = NULL, null.args = NULL, wght.args = NULL, W = NULL,
give.warnings = TRUE,
mean.obj = NA,
sd.obj = NA,
...)
# the verbose switch prints many intermediate steps as an aid in debugging.
#
{
#
# create output list
out <- list()
###########################################################
# First series of steps simply store pieces of the passed
# information to the output list (i.e. the Krig object)
##########################################################
out$call <- match.call()
# turn off warning based on options
if( options()$warn < 0 ){
give.warnings<- FALSE
}
if( !is.na(mean.obj)|!is.na(sd.obj)){
stop( "correlation model no longer supported please use
fields version 11.6")
}
#
# save covariance function as its name
#
if( !is.character( cov.function)){
out$cov.function.name <- as.character(substitute(cov.function))
}
else{
out$cov.function.name<-cov.function
}
#
# save null space function as its name
#
out$null.function.name <- as.character(substitute(null.function))
#
# save weight function as its name if it is not a NULL
#
if (is.null(wght.function)) {
out$wght.function.name <- NULL
}
else {
out$wght.function.name <- as.character(substitute(wght.function))
}
out$W <- W
if (verbose) {
print(out$cov.function.name)
print(out$null.function.name)
print(out$wght.function.name)
}
#
# logical to indicate if the 'C' argument is present in cov.function
# -- a bit of esoteric R code!
C.arg.missing <- all(names(formals(get(out$cov.function.name))) !=
"C")
if (C.arg.missing)
stop("Need to have C argument in covariance function\nsee Exp.cov.simple as an example")
#
# save parameters values possibly passed to the covariance function
# also those added to call are assumed to be covariance arguments.
if (!is.null(cov.args))
out$args <- c(cov.args, list(...))
else out$args <- list(...)
#
# default values for null space function
out$null.args <- null.args
#
# set degree of polynomial null space if this is default
# mkpoly is used so often is it helpful to include m argument
# by default in Krig call.
if (out$null.function.name == "Krig.null.function") {
out$null.args <- list(m = m)
out$m <- m
}
#
# default values for Cholesky decomposition, these are important
# for sparse matrix decompositions used in Krig.engine.fixed.
if (is.null(chol.args)) {
out$chol.args <- list(pivot = FALSE)
}
else {
out$chol.args <- chol.args
}
# additional arguments for weight matrix.
out$wght.args <- wght.args
#
# the offset is the effective number of parameters used in the GCV
# calculations -- unless this is part of an additive model this
# is likely zero
out$offset <- offset
#
# the cost is the multiplier applied to the GCV eff.df
#
# lambda and df are two ways of parameterizing the smoothness
# and are related by a monotonic function that unfortunately
# depends on the locations of the data.
# lambda can be used directly in the linear algebra, df
# must be transformed to lambda numerically using the monotonic trransformation
# tau2 is the error variance and sigma the multiplier for the covariance
# method is how to determine lambda
# the GCV logical forces the code to do the more elaborate decompositions
# that faclitate estimating lambda -- even if a specific lambda value is
# given.
out$cost <- cost
out$lambda <- lambda
out$eff.df <- df
out$tau2 <- tau2
out$sigma <- sigma
out$method <- method
out$GCV <- GCV
#
# correlation model information
# set this to FALSE -- has been depreciated.
#
out$correlation.model <- FALSE
#
# transformation info
out$scale.type <- scale.type
out$x.center <- x.center
out$x.scale <- x.scale
#
if (verbose) {
cat(" Cov function arguments in call ", fill = TRUE)
print(out$args)
cat(" covariance function used is : ", fill = TRUE)
print(out$cov.function.name)
}
###############################################################
# Begin modifications and transformations of input information
# note that many of these manipulations follow a strategy
# of passing the Krig object (out) to a function and
# then appending the information from this function to
# the Krig object (usually also called "out").
#In this way the Krig object is built up
# in steps and the process is easier to follow.
###############################################################
# various checks on x and Y including removal of NAs in Y
# Here is an instance of adding to the Krig object
# in this case also some onerous bookkeeping making sure arguments are consistent
out2 <- Krig.check.xY(x, Y, Z, weights, na.rm, verbose = verbose)
out <- c(out, out2)
# find replicates and collapse to means and pool variances.
# Transform unique x locations
out2 <- Krig.transform.xY(out, verbose = verbose)
out <- c(out, out2)
# NOTE: knots have been transformed after this step
#############################################################
# Figure out what to do
#############################################################
#
# this functions works through the logic of
# what has been supplied for lambda
out2 <- Krig.which.lambda(out)
out[names(out2)] <- out2
# Make weight matrix for observations
# ( this is proportional to the inverse square root of obs covariance)
# if a weight function or W has not been passed then this is
# diag( out$weightsM) for W
# The checks represent a limitation of this model to
# the WBW type decoposition and no replicate observations.
out$nondiag.W <- (!is.null(wght.function)) | (!is.null(W))
# Do not continue if there there is a nondiagonal weight matrix
# and replicate observations.
if (out$nondiag.W) {
if (out$knot.model | out$fixed.model) {
stop("Non diagonal weight matrix for observations
not supported\nwith knots or fixed lambda.")
}
if (!is.na(out$tauHat.pure.error)) {
stop("Non diagonal weight matrix not implemented
with replicate locations")
}
}
# make weight matrix and its square root having passed checks
out <- c(out, Krig.make.W(out, verbose = verbose))
# Do the intensive linear algebra to find the solutions
# this is where all the heavy lifting happens.
#
# Note that all the information is passed as a list
# including arguments to the cholesky decomposition
# used within Krig.engine.fixed
#
# The results are saved in the component matrices
#
# if method=='user' then just evaluate at single lambda
# fixed here means a fixed lambda
#
# For fixed lambda the decompositions with and without knots
# are surprisingly similar and so are in one engine.
###########################################################
if (out$fixed.model) {
out$matrices <- Krig.engine.fixed(out, verbose = verbose)
# The trace of A matrix in fixed lambda case is not easily computed
# so set this to NA.
out$eff.df <- NA
}
# alternative are
# matrix decompositions suitable for
# evaluation at many lambdas to facilitate GCV/REML estimates etc.
#
else{
# standard engine following the basic computations for thin plate splines
out$matrices <- Krig.engine.default(out, verbose = verbose)
# store basic information about decompositions
}
out$nt <- out$matrices$nt
out$np <- out$matrices$np
out$decomp <- out$matrices$decomp
#
# Now determine a logical vector to indicate coefficients tied to the
# the 'spatial drift' i.e. the fixed part of the model
# that is not due to the Z covariates.
# NOTE that the spatial drift coefficients must be the first columns of the
# M matrix
if (is.null(out$Z)) {
out$ind.drift <- rep(TRUE, out$nt)
}
else {
mZ <- ncol(out$ZM)
out$ind.drift <- c(rep(TRUE, out$nt - mZ), rep(FALSE,
mZ))
}
if (verbose) {
cat("null df: ", out$nt, "drift df: ", sum(out$ind.drift),
fill = TRUE)
}
#################################################
# Do GCV and REML search over lambda if not fixed or if GCV variable is TRUE
# also does a search over likelihood for lambda.
#################################################
if (!out$fixed.model | out$GCV) {
if (verbose) {
cat("call to KrigFindLambda", fill = TRUE)
}
gcv.out <- KrigFindLambda(out, nstep.cv = nstep.cv, verbose = verbose,
cost = out$cost, offset = out$offset, give.warnings=FALSE)
out$gcv.grid <- gcv.out$gcv.grid
# save a handy summary table of the search results
out$lambda.est <- gcv.out$lambda.est
out$warningTable<- gcv.out$warningTable
if( verbose){
cat("summaries from grid search/optimization", fill=TRUE)
print(out$lambda.est)
print(out$warningTable)
}
if( give.warnings){
#NOTE: only print out grid search warning for the method of interest.
printGCVWarnings( gcv.out$warningTable, method=method)
}
# assign the preferred lambda either from GCV/REML/MSE or the user value
# NOTE: gcv/reml can be done but the estimate is
# still evaluted at the passed user values of lambda (or df)
# If df is passed need to calculate the implied lambda value
if (out$method != "user") {
out$lambda <- gcv.out$lambda.est[out$method, 1]
out$eff.df <- out$lambda.est[out$method, 2]
}
else {
if (!is.na(out$eff.df)) {
out$lambda <- Krig.df.to.lambda(out$eff.df, out$matrices$D)
}
else {
out$eff.df <- Krig.ftrace(out$lambda, out$matrices$D)
}
# add in values to GCV table using these values
# this the 7th row.
lam.user <- out$lambda
info<- gcv.out$info
newRow<- c( lam.user,
out$eff.df,
Krig.fgcv(lam.user, info),
sqrt(Krig.fs2hat(lam.user, info)),
Krig.flplike(lam.user, info),
NA
)
out$lambda.est <-
rbind( out$lambda.est,user = newRow)
}
}
##########################
# end GCV/REML block
##########################
#
# Now we clean up what has happened and stuff
# information into output object.
#
##########################################
# find coeficients at prefered lambda
# and evaluate the solution at observations
##########################################
# pass replicate group means -- no need to recalculate these.
out2 <- Krig.coef(out, yM = out$yM, verbose = verbose)
out <- c(out, out2)
#######################################################################
# fitted values and residuals and predicted values for full model and
# also on the null space (fixed
# effects). But be sure to do this at the nonmissing x's.
##################################################################
out$fitted.values <- predict.Krig(out, x = out$x, Z = out$Z,
eval.correlation.model = FALSE)
out$residuals <- out$y - out$fitted.values
#
# this is just M%*%d note use of do.call using function name
Tmatrix <- do.call(out$null.function.name, c(out$null.args,
list(x = out$x, Z = out$Z)))
out$fitted.values.null <- as.matrix(Tmatrix) %*% out$d
#
# verbose block
if (verbose) {
cat("residuals", out$residuals, fill = TRUE)
}
#
# find various estimates of tau and sigma
out2 <- Krig.parameters(out)
out <- c(out, out2)
################################################
# assign the 'best' model as a default choice
# either use the user supplied values or the results from
# optimization
################################################
passed.tau2 <- (!is.na(out$tau2))
if (out$method == "user" & passed.tau2) {
out$best.model <- c(out$lambda, out$tau2, out$sigma)
}
else {
# in this case lambda is from opt. or supplied by user
out$best.model <- c(out$lambda, out$tauHat.MLE^2, out$sigmahat)
}
# Note: values in best.model are used in subsquent functions as the choice
# for these parameters!
# set class
##########################
out$rhohat<- out$sigmahat
class(out) <- c("Krig")
return(out)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.