R/mcmcarray-object.r

Defines functions hist.mcmcarray.list hist.mcmcarray density.mcmcarray.list density.mcmcarray summary.mcmcarray.list summary.mcmcarray biips_hist.mcmcarray.list biips_density.mcmcarray.list biips_table.mcmcarray.list biips_hist.mcmcarray biips_hist biips_density.mcmcarray biips_table.mcmcarray print.summary.mcmcarray.list print.summary.mcmcarray biips_summary.mcmcarray.list biips_summary.mcmcarray print.mcmcarray.list print.mcmcarray is.mcmcarray.list is.mcmcarray mcmcarray

Documented in biips_density.mcmcarray biips_density.mcmcarray.list biips_hist biips_hist.mcmcarray biips_hist.mcmcarray.list biips_summary.mcmcarray biips_summary.mcmcarray.list biips_table.mcmcarray biips_table.mcmcarray.list density.mcmcarray density.mcmcarray.list hist.mcmcarray hist.mcmcarray.list is.mcmcarray is.mcmcarray.list mcmcarray mcmcarray summary.mcmcarray summary.mcmcarray.list

#' @title Objects for representing MCMC output.
#'
#' @description A \code{mcmcarray} object is returned by the
#'   \code{\link{biips_pimh_samples}} or \code{\link{biips_pmmh_samples}}
#'   functions to represent MCMC output of a given variable.
#'
#'   A \code{mcmcarray.list} object is a named list of \code{mcmcarray} objects
#'   for different monitored variables.
#'
#'   The methods apply identically to \code{mcmcarray} or \code{mcmcarray.list}
#'   objects and return a named list with the same named members as the input
#'   object.
#'
#' @name mcmcarray-object
#' @aliases mcmcarray.list-object mcmcarray mcmcarray.list
#' @param object,x a \code{mcmcarray} or \code{mcmcarray.list} object.
#' @param ... additional arguments to be passed to the default methods. See
#'   \code{\link[stats]{density}}, \code{\link[graphics]{hist}},
#'   \code{\link[base]{table}}
#'
#' @return The methods apply identically to \code{mcmcarray} or
#'   \code{mcmcarray.list} objects and return a named list with the same named
#'   members as the input object.
#'
#' @examples
#' modelfile <- system.file('extdata', 'hmm.bug', package = 'rbiips')
#' stopifnot(nchar(modelfile) > 0)
#' cat(readLines(modelfile), sep = '\n')
#'
#' #' # PIMH algorithm
#' data <- list(tmax = 10, p = c(.5, .5), logtau_true = log(1), logtau = log(1))
#' model <- biips_model(modelfile, data, sample_data = TRUE)
#'
#' n_part <- 50
#' obj_pimh <- biips_pimh_init(model, c('x', 'c[2:10]'))  # Initialize
#' out_pimh_burn <- biips_pimh_update(obj_pimh, 100, n_part)  # Burn-in
#' out_pimh <- biips_pimh_samples(obj_pimh, 100, n_part)  # Samples
#'
#' #' Manipulate `mcmcarray.list` object
#' is.mcmcarray.list(out_pimh)
#' names(out_pimh)
#' out_pimh
#' biips_summary(out_pimh)
#'
#' #' Manipulate `mcmcarray` object
#' is.mcmcarray(out_pimh$x)
#' out_pimh$x
#' summ_pimh_x <- biips_summary(out_pimh$x, order = 2, probs = c(0.025, 0.975))
#' summ_pimh_x
#' dens_pimh_x <- biips_density(out_pimh$x)
#' par(mfrow = c(2, 2))
#' plot(dens_pimh_x)
#' par(mfrow = c(2, 2))
#' biips_hist(out_pimh$x)
#'
#' is.mcmcarray(out_pimh[['c[2:10]']])
#' out_pimh[['c[2:10]']]
#' summ_pimh_c <- biips_summary(out_pimh[['c[2:10]']])
#' summ_pimh_c
#' table_pimh_c <- biips_table(out_pimh[['c[2:10]']])
#' par(mfrow = c(2, 2))
#' plot(table_pimh_c)
#'
#' #' # PMMH algorithm
#' data <- list(tmax = 10, p = c(.5, .5), logtau_true = log(1))
#' model <- biips_model(modelfile, data)
#'
#' n_part <- 50
#' obj_pmmh <- biips_pmmh_init(model, 'logtau', latent_names = c('x', 'c[2:10]'),
#'                             inits = list(logtau = -2))  # Initialize
#' out_pmmh_burn <- biips_pmmh_update(obj_pmmh, 100, n_part)  # Burn-in
#' out_pmmh <- biips_pmmh_samples(obj_pmmh, 100, n_part, thin = 1)  # Samples
#'
#' #' Manipulate `mcmcarray.list` object
#' is.mcmcarray.list(out_pmmh)
#' names(out_pmmh)
#' out_pmmh
#' biips_summary(out_pmmh)
#'
#' #' Manipulate `mcmcarray` object
#' is.mcmcarray(out_pmmh$logtau)
#' out_pmmh$logtau
#' summ_pmmh_lt <- biips_summary(out_pmmh$logtau, order = 2, probs = c(0.025, 0.975))
#' dens_pmmh_lt <- biips_density(out_pmmh$logtau)
#' par(mfrow = c(2, 1))
#' plot(dens_pmmh_lt)
#' biips_hist(out_pmmh$logtau)
#'
#' is.mcmcarray(out_pmmh$x)
#' out_pmmh$x
#' summ_pmmh_x <- biips_summary(out_pmmh$x, order = 2, probs = c(0.025, 0.975))
#' dens_pmmh_x <- biips_density(out_pmmh$x)
#' par(mfrow = c(2, 2))
#' plot(dens_pmmh_x)
#' par(mfrow = c(2, 2))
#' biips_hist(out_pmmh$x)
#'
#' is.mcmcarray(out_pmmh[['c[2:10]']])
#' out_pmmh[['c[2:10]']]
#' summ_pmmh_c <- biips_summary(out_pmmh[['c[2:10]']])
#' table_pmmh_c <- biips_table(out_pmmh[['c[2:10]']])
#' par(mfrow = c(2, 2))
#' plot(table_pmmh_c)
NULL

#' @rdname mcmcarray-object
#' @param data      numerical vector
#' @param dim       vector of integers. dimension of the array
#' @param dimnames  character vector
#' @param iteration integer. index of the dimension corresponding to iterations
#'   of the MCMC.
#' @param chain     integer. index of the dimension corresponding to chain of
#'   the MCMC.
#' @param name   string. variable name
#' @param lower   vector of integers. variable lower bound
#' @param upper   vector of integers. variable upper bound
#' @return The \code{mcmcarray} function returns an object of class \code{mcmcarray}.
mcmcarray <- function(data = NA, dim = length(data), dimnames = NULL, iteration = length(dim),
  chain = NA, name = "mcmcarray", lower = NULL, upper = NULL) {
  stopifnot(length(iteration) == 1, length(chain) == 1)
  if (is.na(iteration))
    stopifnot(is.na(chain)) else {
    stopifnot(is.numeric(iteration), iteration >= 1, iteration <= length(dim))
    if (!any(is.na(chain)))
      stopifnot(is.numeric(chain), chain >= 1, chain <= length(dim), chain !=
        iteration)
  }

  x <- array(data, dim, dimnames)

  nd <- names(dim(x))
  nd[iteration] <- "iteration"
  nd[chain] <- "chain"
  names(dim(x)) <- nd

  drop_dims <- names(dim(x)) %in% c("iteration", "chain")
  dim_array <- dim(x)[!drop_dims]

  if (is.null(lower)) {
    lower <- rep(1, length(dim_array))
  }
  if (is.null(upper)) {
    upper <- dim_array
  }

  attr(x, "name") <- name
  attr(x, "lower") <- lower
  attr(x, "upper") <- upper

  class(x) <- "mcmcarray"
  return(x)
}


#' @export
#' @rdname mcmcarray-object
#' @return The function \code{is.mcmcarray} returns \code{TRUE} if the object is
#'   of class \code{mcmcarray}.
is.mcmcarray <- function(object) {
  return(class(object) == "mcmcarray")
}

#' @export
#' @rdname mcmcarray-object
#' @return The function \code{is.mcmcarray.list} returns \code{TRUE} if the
#'   object is of class \code{mcmcarray.list}.
is.mcmcarray.list <- function(object) {
  return(class(object) == "mcmcarray.list")
}

#' @export
print.mcmcarray <- function(x, ...) {
  print(summary(x), ...)
}

#' @export
print.mcmcarray.list <- function(x, ...) {
  print(summary(x), ...)
}

#' @export
#' @rdname mcmcarray-object
#' @inheritParams biips_summary.smcarray
#' @return The method \code{biips_summary} returns univariate marginal
#'   statistics. The output innermost members are objects of class
#'   \code{summary.mcmcarray}, \emph{i.e.} lists with members:
#'   \item{mean}{mean, if \code{order>=1}.}
#'   \item{var}{variance, if \code{order>=2}.}
#'   \item{skew}{skewness, if \code{order>=3}.}
#'   \item{kurt}{kurtosis, if \code{order>=4}.}
#'   \item{probs}{vector of quantile probabilities.}
#'   \item{quant}{list of quantile values, if \code{probs} is not empty.}
#'   \item{mode}{most frequent values for discrete components.}
#' @importFrom stats var quantile
biips_summary.mcmcarray <- function(object, probs = c(), order = ifelse(mode, 0,
  1), mode = all(object == as.integer(object)), ...) {
  stopifnot(is.mcmcarray(object))

  ### TODO check arguments
  if (length(probs) > 0)
    stopifnot(is.numeric(probs), probs > 0, probs < 1)

  drop_dims <- names(dim(object)) %in% c("iteration", "chain")
  dim_array <- dim(object)[!drop_dims]
  marg <- which(!drop_dims)
  summ <- list()

  ### moment based statistics
  if (order >= 1)
    summ$mean <- apply(object, marg, FUN = mean)

  if (order >= 2)
    summ$var <- apply(object, marg, FUN = var)

  if (order >= 3) {
    mom2 <- apply(object^2, marg, FUN = mean)
    mom3 <- apply(object^3, marg, FUN = mean)
    summ$skew <- (mom3 - 3 * mom2 * summ$mean + 2 * summ$mean^3)/summ$var^(3/2)
  }

  if (order >= 4) {
    mom4 <- apply(object^4, marg, FUN = mean)
    summ$kurt <- (mom4 - 4 * mom3 * summ$mean + 6 * mom2 * summ$mean^2 - 3 *
      summ$mean^4)/summ$var^2 - 3
  }

  ### quantiles
  if (length(probs) > 0) {
    summ$probs <- probs
    quant <- apply(object, marg, FUN = quantile, probs = probs, names = FALSE)
    ndim <- length(dim(quant))
    quant <- aperm(quant, c(2:ndim, 1))

    len <- prod(dim_array)
    summ$quant <- list()
    for (i in 1:length(probs)) {
      summ$quant[[as.character(probs[i])]] <- array(quant[((i - 1) * len +
        1):(i * len)], dim = dim_array)
    }
  }

  ### mode
  if (mode) {
    summ$mode <- apply(object, marg, FUN = function(x) as.numeric(names(which.max(table(x)))))
  }

  summ$drop.dims <- dim(object)[drop_dims]

  class(summ) <- "summary.mcmcarray"

  return(summ)
}

#' @export
#' @rdname mcmcarray-object
biips_summary.mcmcarray.list <- function(object, ...) {
  stopifnot(is.mcmcarray.list(object))
  ans <- list()
  for (n in names(object)) {
    if (!is.mcmcarray(object[[n]]))
      next
    ans[[n]] <- biips_summary(object[[n]], ...)
  }

  class(ans) <- "summary.mcmcarray.list"

  return(ans)
}

#' @export
print.summary.mcmcarray <- function(x, ...) {
  cat("mcmcarray:\n")
  print(x[!(names(x) %in% c("drop.dims"))], ...)
  if (length(x$drop.dims) > 0) {
    cat("Marginalizing over:", paste(paste(names(x$drop.dims), "(", x$drop.dims,
      ")", sep = ""), collapse = ","), "\n")
  }
}


#' @export
print.summary.mcmcarray.list <- function(x, ...) {
  for (n in names(x)) {
    if (n %in% c("log_marg_like_pen", "log_marg_like", "info"))
      next
    cat(n, " ", sep = "")
    print(x[[n]], ...)
    cat("\n")
  }
  invisible()
}

#' @export
#' @rdname mcmcarray-object
#' @return The method \code{biips_table} returns univariate marginal frequency
#'   tables or probability mass estimates of discrete variables. The output
#'   innermost members are objects of class \code{table.mcmcarray}.
biips_table.mcmcarray <- function(x, ...) {
  stopifnot(is.mcmcarray(x))
  out <- list()

  dimen <- dim(x)
  drop_dim <- names(dimen) %in% c("iteration", "chain")
  n_samples <- prod(dimen[drop_dim])
  len <- prod(dimen[!drop_dim])

  for (d in 1:len) {
    ind_vec <- seq(d, len * (n_samples - 1) + d, len)
    values <- x[ind_vec]

    l <- attr(x, "lower")
    u <- attr(x, "upper")
    ind <- l + get_index(d, rep(0, length(l)), u - l)
    dnn <- deparse_varname(attr(x, "name"), ind, ind)

    out[[d]] <- table(values, dnn = dnn, ...)/n_samples
  }

  dim(out) <- dimen[!drop_dim]
  class(out) <- "table.mcmcarray"
  return(out)
}


#' @export
#' @rdname mcmcarray-object
#' @inheritParams biips_density.smcarray
#' @return The method \code{biips_density} returns univariate marginal kernel
#'   density estimates. The output innermost members are objects of class
#'   \code{density.mcmcarray}.
biips_density.mcmcarray <- function(x, bw = "nrd0", ...) {
  stopifnot(is.mcmcarray(x))
  out <- list()

  dimen <- dim(x)
  drop_dim <- names(dimen) %in% c("iteration", "chain")
  n_samples <- prod(dimen[drop_dim])
  len <- prod(dimen[!drop_dim])

  for (d in 1:len) {
    ind_vec <- seq(d, len * (n_samples - 1) + d, len)
    values <- x[ind_vec]

    out[[d]] <- density(values, bw = rec(bw, d), ...)  # recycle bw
    ind <- attr(x, "lower") + get_index(d, rep(0, length(attr(x, "lower"))),
      attr(x, "upper") - attr(x, "lower"))
    out[[d]]$data.name <- deparse_varname(attr(x, "name"), ind, ind)

    class(out[[d]]) <- "density.mcmcarray.univariate"
  }

  dim(out) <- dimen[!drop_dim]
  class(out) <- "density.mcmcarray"
  return(out)
}


#' @export
#' @rdname mcmcarray-object
biips_hist <- function(x, ...) UseMethod("biips_hist")

#' @export
#' @rdname mcmcarray-object
biips_hist.mcmcarray <- function(x, main = NULL, xlab = NULL, ...) {
  stopifnot(is.mcmcarray(x))
  out <- list()

  dimen <- dim(x)
  drop_dim <- names(dimen) %in% c("iteration", "chain")
  n_samples <- prod(dimen[drop_dim])
  len <- prod(dimen[!drop_dim])

  for (d in 1:len) {
    ind_vec <- seq(d, len * (n_samples - 1) + d, len)
    values <- x[ind_vec]

    ind <- attr(x, "lower") + get_index(d, rep(0, length(attr(x, "lower"))),
      attr(x, "upper") - attr(x, "lower"))
    xname <- deparse_varname(attr(x, "name"), ind, ind)

    main_ <- rec(main, d)
    if (is.null(main_)) {
      main_ <- paste("Histogram of", xname)
    }

    out[[d]] <- hist(values, main = main_, xlab = rec(xlab, d), ...)  # recycle arguments
    out[[d]]$xname <- xname
  }

  dim(out) <- dimen[!drop_dim]
  class(out) <- "histogram.mcmcarray"
  return(invisible(out))
}

#' @export
#' @rdname mcmcarray-object
biips_table.mcmcarray.list <- function(x, ...) {
  stopifnot(is.mcmcarray.list(x))
  out <- list()
  for (i in 1:length(x)) {
    name <- names(x)[i]
    if (!is.mcmcarray(x[[i]]) || name %in% c("log_marg_like_pen", "log_marg_like",
      "info"))
      next
    out[[name]] <- biips_table(x[[i]], ...)
  }
  class(out) <- "table.mcmcarray.list"
  return(out)
}

#' @export
#' @rdname mcmcarray-object
biips_density.mcmcarray.list <- function(x, bw = "nrd0", ...) {
  stopifnot(is.mcmcarray.list(x))
  out <- list()
  for (i in 1:length(x)) {
    name <- names(x)[i]
    if (!is.mcmcarray(x[[i]]) || name %in% c("log_marg_like_pen", "log_marg_like",
      "info"))
      next
    out[[name]] <- biips_density(x[[i]], bw = rec(bw, i), ...)  # recycle bw
  }
  class(out) <- "density.mcmcarray.list"
  return(out)
}

#' @export
#' @rdname mcmcarray-object
#' @param main,xlab plotting parameters with useful defaults.
biips_hist.mcmcarray.list <- function(x, main = NULL, xlab = NULL, ...) {
  stopifnot(is.mcmcarray.list(x))
  out <- list()
  for (i in 1:length(x)) {
    name <- names(x)[i]
    if (!is.mcmcarray(x[[i]]) || name %in% c("log_marg_like_pen", "log_marg_like",
      "info"))
      next
    out[[name]] <- biips_hist(x[[i]], main = rec(main, i), xlab = rec(xlab, i),
      ...)  # recycle arguments
  }
  class(out) <- "histogram.mcmcarray.list"
  return(invisible(out))
}


#' @export
#' @rdname mcmcarray-object
#' @return The method \code{summary} is an alias for \code{biips_summary}.
summary.mcmcarray <- function(object, ...) {
  return(biips_summary(object, ...))
}
#' @export
#' @rdname mcmcarray-object
summary.mcmcarray.list <- function(object, ...) {
  return(biips_summary(object, ...))
}

#' @importFrom stats density
#' @export
#' @rdname mcmcarray-object
#' @return The method \code{density} is an alias for \code{biips_density}.
#' @seealso \code{\link[stats]{density}}
density.mcmcarray <- function(x, ...) {
  return(biips_density(x, ...))
}
#' @export
#' @rdname mcmcarray-object
density.mcmcarray.list <- function(x, ...) {
  return(biips_density(x, ...))
}
#' @importFrom graphics hist
#' @export
#' @rdname mcmcarray-object
#' @return The method \code{hist} is an alias for \code{biips_hist}.
hist.mcmcarray <- function(x, ...) {
  return(biips_hist(x, ...))
}
#' @export
#' @rdname mcmcarray-object
hist.mcmcarray.list <- function(x, ...) {
  return(biips_hist(x, ...))
}
biips/rbiips documentation built on Nov. 28, 2020, 2:12 p.m.