R/jagshelper1.R

Defines functions niggle rcolors expit logit jags_plist pull_post jags_df skeleton

Documented in expit jags_df jags_plist logit pull_post rcolors skeleton

#' Skeleton
#' @description Prints an example 'JAGS' model and associated 'jagsUI' code to
#' the console, along with code to simulate a corresponding dataset.  This is
#' intended to serve as a template that can be altered as needed by the user.
#' @param NAME Name to append to JAGS model object, etc.
#' @return `NULL`
#' @note The printed code will use the `cat()` function to write the model code to an
#' external text file.  It may be desirable to use a call to `\link{tempfile}()`
#' instead, to eliminate creation of unneeded files.
#' @author Matt Tyers
#' @importFrom grDevices adjustcolor rainbow
#' @importFrom graphics axis lines par points polygon segments
#' @importFrom stats density quantile
#' @importFrom grDevices rgb
#' @importFrom graphics abline legend rect text
#' @importFrom stats rbeta median cor
#' @examples
#' skeleton("asdf")
#' @export
skeleton <- function(NAME="NAME") {
cat("
library(jagsUI)

# specify model, which is written to a temporary file
",NAME,"_jags <- tempfile()
cat('model {
  for(i in 1:n) {
    y[i] ~ dnorm(mu[i], tau)
    mu[i] <- b0 + b1*x[i] + a[grp[i]]
  }

  for(j in 1:ngrp) {
    a[j] ~ dnorm(0, tau_a)
  }

  tau <- pow(sig, -2)
  sig ~ dunif(0, 10)
  b0 ~ dnorm(0, 0.001)
  b1 ~ dnorm(0, 0.001)

  tau_a <- pow(sig_a, -2)
  sig_a ~ dunif(0, 10)
}', file=",NAME,"_jags)


# simulate data to go with the example model
n <- 60
x <- rnorm(n, sd=3)
grp <- sample(1:3, n, replace=T)
y <- rnorm(n, mean=grp-x)

# bundle data to pass into JAGS
",NAME,"_data <- list(x=x,
                 y=y,
                 n=length(x),
                 grp=as.numeric(as.factor(grp)),
                 ngrp=length(unique(grp)))

# JAGS controls
niter <- 10000
ncores <- 3
# ncores <- min(10, parallel::detectCores()-1)

{
  tstart <- Sys.time()
  print(tstart)
  ",NAME,"_jags_out <- jagsUI::jags(model.file=",NAME,"_jags, data=",NAME,"_data,
                             parameters.to.save=c(\"b0\",\"b1\",\"sig\",\"a\",\"sig_a\"),
                             n.chains=ncores, parallel=T, n.iter=niter,
                             n.burnin=niter/2, n.thin=niter/2000)
  print(Sys.time() - tstart)
}

nbyname(",NAME,"_jags_out)
plotRhats(",NAME,"_jags_out)
traceworstRhat(",NAME,"_jags_out, parmfrow = c(3, 3))",sep="")
}

#' Extract data.frame
#' @description Extracts the posterior samples from `jagsUI` output in the form of
#' a `data.frame`.  This simpler construction has a few benefits: operations may
#' be more straightforward, and posterior objects will be smaller files and can be
#' written to an external table or .csv, etc.
#' @param x Output object from `jagsUI::jags()`
#' @param p Optional string to begin posterior names.  If `NULL` is used, all parameters will be returned.
#' @param exact Whether name must be an exact match (`TRUE`) or with initial sub-string matching only supplied characters (`FALSE`).
#' Defaults to `FALSE.`
#' @return A `data.frame` with a column associated with each parameter and a row
#' associated with each MCMC iteration.
#' @seealso \link{pull_post}
#' @author Matt Tyers
#' @import jagsUI
#' @examples
#' out_df <- jags_df(asdf_jags_out)
#' @export
jags_df <- function(x, p=NULL, exact=FALSE) {
  if(!inherits(x,"jagsUI")) stop("Input must be an output object returned from jagsUI::jags().")
  xdf <- as.data.frame(as.matrix(x$samples))
  if(!is.null(p)) xdf <- pull_post(xdf, p=p, exact=exact)
  return(xdf)
}


#' Subset from posterior data.frame
#' @description Extracts a subset vector or `data.frame` from a `data.frame` consisting of more columns,
#' such that column names match a name given in the `p=` argument.  This may be useful
#' in creating smaller objects consisting of MCMC samples.
#' @param x Posterior `data.frame`
#' @param p String to begin posterior names.  If `NULL` is used, all parameters will be returned.
#' @param exact Whether name must be an exact match (`TRUE`) or with initial sub-string matching only supplied characters (`FALSE`).
#' Defaults to `FALSE.`
#' @return A `data.frame` with a column associated with each (subsetted) parameter and a row
#' associated with each MCMC iteration.
#' @seealso \link{jags_df}
#' @author Matt Tyers
#' @examples
#' out_df <- jags_df(asdf_jags_out)
#'
#' b <- pull_post(out_df, p="b")
#' str(b)
#' a <- pull_post(out_df, p=c("a","sig_a"))
#' str(a)
#' sigs <- pull_post(out_df, p="sig")
#' str(sigs)
#' justsig <- pull_post(out_df, p="sig", exact=TRUE)
#' str(justsig)
#' @export
pull_post <- function(x, p=NULL, exact=FALSE) {
  # # x[,substr(names(x),1,nchar(p))==p]
  # if(!inherits(x,"data.frame")) stop("Input must be a data.frame")
  #
  # if(is.null(p)) {
  #   these <- rep(T, length(names(x)))
  # } else {
  #   these <- rep(F, length(names(x)))  ## used to be F
  #   for(i in 1:length(p)) {
  #     if(exact) {
  #       these[names(x)==p[i]] <- T
  #     } else {
  #       these[substr(names(x),1,nchar(p[i]))==p[i]] <- T
  #     }
  #   }
  #   if(sum(these)==0) warning("No parameters with matching names, returning empty data.frame")
  # }
  # return(x[these])
  if(!inherits(x,"data.frame")) stop("Input must be a data.frame")

  if(is.null(p)) {
    these <- rep(T, length(names(x)))
    return(x)
  } else {
    these <- rep(F, length(names(x)))  ## used to be F
    asalist <- list()
    for(i in 1:length(p)) {
      if(exact) {
        these[names(x)==p[i]] <- T
        asalist[[i]] <- x[names(x)==p[i]]
      } else {
        these[substr(names(x),1,nchar(p[i]))==p[i]] <- T
        asalist[[i]] <- x[substr(names(x),1,nchar(p[i]))==p[i]]
      }
    }
    if(sum(these)==0) warning("No parameters with matching names, returning empty data.frame")
  }
  # return(x[these])
  return(do.call(cbind, asalist))
}

# pull_post1 <- function(x, p=NULL, exact=FALSE) {
#   # x[,substr(names(x),1,nchar(p))==p]
#   if(!inherits(x,"data.frame")) stop("Input must be a data.frame")
#
#   if(is.null(p)) {
#     these <- rep(T, length(names(x)))
#   } else {
#     these <- rep(F, length(names(x)))  ## used to be F
#     asalist <- list()
#     for(i in 1:length(p)) {
#       if(exact) {
#         these[names(x)==p[i]] <- T
#         asalist[[i]] <- x[names(x)==p[i]]
#       } else {
#         these[substr(names(x),1,nchar(p[i]))==p[i]] <- T
#         asalist[[i]] <- x[substr(names(x),1,nchar(p[i]))==p[i]]
#       }
#     }
#     if(sum(these)==0) warning("No parameters with matching names, returning empty data.frame")
#   }
#   # return(x[these])
#   return(do.call(cbind, asalist))
# }
# xx <- pull_post1(out_df, p=c("a","sig","b"))
# xx <- pull_post1(out_df, p=c("a","sig","b"), exact=T)
# xx <- pull_post1(out_df, p=c("a","sig","b","bob"), exact=T)
# xx <- pull_post1(out_df, p=c("bob"), exact=T)


#' Plist
#' @description Extracts a list of matrices, one for each saved parameter node.  Each
#' list element will be all posterior samples from that parameter node, arranged in
#' a matrix with a column associated with each MCMC chain and a row for
#' each MCMC iteration.
#' @param x `jagsUI` output object
#' @param p String to subset parameter names, if a subset is desired
#' @param exact Whether `p` should be an exact match (`TRUE`) or just match the
#' beginning of the string (`FALSE`).  Defaults to `FALSE`.
#' @return A `list` with an element associated with each parameter.  Each element
#' will be a matrix with a column associated with each MCMC chain and a row for
#' each MCMC iteration.
#' @note It is unlikely that a user will need this function; it is included
#' primarily as a helper function used by other functions in this package.
#' @author Matt Tyers
#' @examples
#' out_plist <- jags_plist(asdf_jags_out)
#' str(out_plist)
#'
#' a_plist <- jags_plist(asdf_jags_out, p=c("a","sig_a"))
#' str(a_plist)
#' @export
jags_plist <- function(x, p=NULL, exact=FALSE) {
  if(!inherits(x,"jagsUI")) stop("Input must be an output object returned from jagsUI::jags().")

  x_dflist <- lapply(x$samples, as.data.frame)
  x2 <- lapply(1:length(x_dflist[[1]]), function(x) sapply(x_dflist,
                                                           "[[", x))
  names(x2) <- names(x_dflist[[1]])
  these <- rep(F, length(x2))
  if (!is.null(p)) {
    for(i in 1:length(p)) {
      if(!exact) {
        these[substr(names(x2), 1, nchar(p[i])) == p[i]] <- T
      } else {
        these[names(x2) == p[i]] <- T
      }
      # these[sapply(strsplit(names(x2), split="\\["), FUN="[", 1)==p[i]] <- T   # this is a weird hack
    }
    x2 <- x2[these]
  }
  if(length(x2)==0) warning("No parameters with matching names, returning empty list")
  return(x2)
}












#' Logit
#' @description Logit log(x/(1-x))
#' @param x Numeric vector
#' @return Numeric vector
#' @seealso \link{expit}
#' @author Matt Tyers
#' @examples
#' logit(0.5)
#' @export
logit <- function(x) log(x/(1-x))


#' Expit, or inverse logit
#' @description Inverse logit, where logit is defined as log(x/(1-x)).
#'
#' Expit (inverse logit) is defined as exp(x)/(1+exp(x)).
#' @param x Numeric vector
#' @return Numeric vector
#' @seealso \link{logit}
#' @author Matt Tyers
#' @examples
#' expit(0)
#' @export
expit <- function(x) exp(x)/(1+exp(x))












#' Example data: asdf jags out
#'
#' A simple model, equivalent to that produced by the output produced by `\link{skeleton}`.
#'
"asdf_jags_out"

#' Example data: asdf prior jags out
#'
#' A simple model, equivalent to that produced by the output produced by `\link{skeleton}`,
#' with the addition of prior samples for all parameters.
#'
"asdf_prior_jags_out"

#' Example data: SS JAGS out
#'
#' A time series model with multiple observations of a single time series, and with two stochastic cycle components.
#'
#' This model is included partly to show a model with vectors or 2-dimensional
#' matrices of parameter nodes, and also to give an example of poor model convergence.
#'
"SS_out"

#' Example data: Time series associated with SS JAGS out
#'
#' The time series and time measurements associated with the time series model `\link{SS_out}`.
#'
"SS_data"






#' Random Colors
#' @description Creates a vector of randomly-generated colors.
#' @param n Vector length
#' @return A vector of colors
#' @author Matt Tyers
#' @examples
#' n <- 1000
#' cols <- rcolors(n)
#' x <- runif(n)
#' y <- runif(n)
#' plot(x,y, col=cols, pch=16)
#' @export
rcolors <- function(n) {
  bparm <- .8
  hi <- .9
  lo <- .1
  rr <- rbeta(n,bparm,bparm)*(hi-lo)+lo#runif(n=n, min=0.3, max=0.8)
  gg <- rbeta(n,bparm,bparm)*(hi-lo)+lo#runif(n=n, min=0.3, max=0.8)
  bb <- rbeta(n,bparm,bparm)*(hi-lo)+lo#runif(n=n, min=0.3, max=0.8)
  cols <- rgb(red=rr, green=gg, blue=bb)
  return(cols)
}







niggle <- function() print("He was the sort of painter who can paint leaves better than trees. ")

Try the jagshelper package in your browser

Any scripts or data that you put into this service are public.

jagshelper documentation built on Oct. 22, 2024, 1:06 a.m.