diff --git a/CRAN-RELEASE b/CRAN-RELEASE
deleted file mode 100644
index 4ba470f..0000000
--- a/CRAN-RELEASE
+++ /dev/null
@@ -1,2 +0,0 @@
-This package was submitted to CRAN on 2019-09-27.
-Once it is accepted, delete this file and tag the release (commit c1541e7383).
diff --git a/DESCRIPTION b/DESCRIPTION
index aa80393..c2e24c8 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,8 +1,8 @@
Package: colorednoise
Type: Package
Title: Simulate Temporally Autocorrelated Populations
-Version: 1.0.5
-Date: 2019-09-26
+Version: 1.1.0
+Date: 2020-08-03
Authors@R: c(
person("Julia", "Pilowsky", email = "jap2178@caa.columbia.edu",
role = c("aut", "cre"), comment = c(ORCID = "0000-0002-6376-2585")
@@ -14,12 +14,11 @@ License: GPL-3
Depends: R (>= 3.3.0)
Imports:
stats (>= 3.3.2),
- dplyr (>= 0.7.3),
purrr (>= 0.2.3),
- tibble (>= 2.0.0),
- tidyr (>= 1.0.0)
+ Rcpp (>= 1.0.5),
+ data.table (>= 1.12.8)
LinkingTo: Rcpp, RcppArmadillo
-RoxygenNote: 6.1.1
+RoxygenNote: 7.1.1
Encoding: UTF-8
LazyData: true
BugReports: http://github.com/japilo/colorednoise/issues
diff --git a/NAMESPACE b/NAMESPACE
index 0439521..ccd4145 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -7,14 +7,13 @@ export(colored_noise)
export(cor2cov)
export(matrix_model)
export(multi_rnorm)
+export(stdev_transform)
export(unstructured_pop)
-import(dplyr)
+import(data.table, except = transpose)
import(purrr)
-import(tidyr)
+importFrom(Rcpp,evalCpp)
importFrom(stats,acf)
importFrom(stats,na.omit)
importFrom(stats,plogis)
importFrom(stats,sd)
-importFrom(tibble,as_tibble)
-importFrom(tibble,tibble)
useDynLib(colorednoise, .registration = TRUE)
diff --git a/NEWS.md b/NEWS.md
index 2ccb6c7..b6835e4 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,10 +1,15 @@
+## colorednoise 1.1.0
+
+* New function exported: `stdev_transform`, which adapts standard deviations to different probability distributions.
+* colorednoise now runs on `data.table` instead of `dplyr`, `tibble`, and `tidyr` for faster simulations.
+
## colorednoise 1.0.5
-* Updated to be compatible with tidyr v1.0.0
+* Updated to be compatible with `tidyr` v1.0.0
## colorednoise 1.0.4
-* Updated to be compatible with tibble v2.0.0
+* Updated to be compatible with `tibble` v2.0.0
## colorednoise 1.0.3
diff --git a/R/RcppExports.R b/R/RcppExports.R
index 6229c60..abe163a 100644
--- a/R/RcppExports.R
+++ b/R/RcppExports.R
@@ -68,18 +68,41 @@ cor2cov <- function(sigma, corrMatrix) {
#' @param covMatrix A valid covariance matrix. The number of rows/columns must match the length of the mu, sigma, and phi vectors.
#' @return A matrix with as many rows as timesteps and as many columns as mu/sigma/phi values.
#' @examples
-#' cov <- matrix(c(0.037, 0.044, -0.048, 0.044, 0.247, -0.008, -0.047, -0.008, 0.074), nrow = 3)
+#' cov <- matrix(c(1, 0.53, 0.73, 0.53, 1, 0.44, 0.73, 0.44, 1), nrow = 3)
#' test <- colored_multi_rnorm(100, c(0, 3, 5), c(1, 0.5, 1), c(0.5, -0.3, 0), cov)
#' var(test)
-#' library(dplyr)
-#' test %>% as.data.frame() %>% summarize_all(.funs = c("mean", "sd", "autocorrelation"))
+#' library(data.table)
+#' as.data.table(test)[, .(V1_mean = mean(V1), V2_mean = mean(V2), V3_mean = mean(V3),
+#' V1_sd = sd(V1), V2_sd = sd(V2), V3_sd = sd(V3),
+#' V1_autocorrelation = autocorrelation(V1), V2_autocorrelation = autocorrelation(V2),
+#' V3_autocorrelation = autocorrelation(V3))]
#' @export
colored_multi_rnorm <- function(timesteps, mean, sd, phi, covMatrix) {
.Call(`_colorednoise_colored_multi_rnorm`, timesteps, mean, sd, phi, covMatrix)
}
-variancefix <- function(mu, sigma, dist) {
- .Call(`_colorednoise_variancefix`, mu, sigma, dist)
+#' Translate Standard Deviation from the Natural Scale to the Log or Logit Scale
+#'
+#' This function changes a given standard deviation so that when a vector of samples is drawn from the given distribution,
+#' the original standard deviation will be recovered once it is back-transformed from the log or logit scale. In effect,
+#' the function "translates" a standard deviation from the natural scale to the log or logit scale for the purposes of
+#' random draws from a probability distribution.
+#' @param mu The mean of the distribution on the natural scale.
+#' @param sigma The standard devation of the distribution on the natural scale.
+#' @param dist The distribution to which the standard deviation should be transformed.
+#' @return The standard deviation translated to the log or logit scale.
+#' @examples
+#' mean <- 10
+#' stdev <- 2
+#' mean_trans <- log(mean)
+#' stdev_trans <- stdev_transform(mean, stdev, "log")
+#' draws <- rnorm(50, mean_trans, stdev_trans)
+#' natural_scale <- exp(draws)
+#' mean(draws)
+#' sd(draws)
+#' @export
+stdev_transform <- function(mu, sigma, dist) {
+ .Call(`_colorednoise_stdev_transform`, mu, sigma, dist)
}
#' Simulated Time Series of an Unstructured Temporally Autocorrelated Population
diff --git a/R/colorednoise.R b/R/colorednoise.R
index bb5ded6..a9e1b46 100644
--- a/R/colorednoise.R
+++ b/R/colorednoise.R
@@ -8,13 +8,12 @@
#' @name colorednoise
#' @useDynLib colorednoise, .registration = TRUE
#' @import purrr
-#' @import dplyr
+#' @importFrom Rcpp evalCpp
+#' @rawNamespace import(data.table, except = transpose)
#' @importFrom stats sd acf na.omit plogis
-#' @importFrom tibble tibble as_tibble
-#' @import tidyr
NULL
## quiets concerns of R CMD check re: the .'s that appear in
## pipelines
if (getRversion() >= "2.15.1") utils::globalVariables(c(".", "mean.trans",
- "sd.trans", "noise", "timestep", "dist", "zero"))
+ "sd.trans", "noise", "timestep", "dist", "zero", "ref"))
diff --git a/R/simulate_populations.R b/R/simulate_populations.R
index 18f6815..eaf9e2f 100644
--- a/R/simulate_populations.R
+++ b/R/simulate_populations.R
@@ -57,8 +57,8 @@ autocorr_sim <- function(timesteps, start, survPhi, fecundPhi, survMean,
}
}
# Unnests the list and adds estimates of survival and fertility
- sims <- labeled_sims %>% flatten() %>% map(~mutate(., est_surv = survivors/population,
- est_fecund = newborns/survivors))
+ sims <- labeled_sims %>% flatten() %>% map(setDT) %>%
+ map(~.[, `:=`(est_surv = survivors/population, est_fecund = newborns/survivors)])
return(sims)
}
@@ -117,10 +117,10 @@ matrix_model <- function(data, initialPop, timesteps, covMatrix = NULL,
colNames = NULL, matrixStructure = NULL, repeatElements = NULL,
survivalOverflow = "scale") {
stages <- length(initialPop)
- # Regularize all valid data inputs to the same format
+ # Regularize all valid data input to the same format
if (is.data.frame(data) == T) {
if (is.null(colNames) == F) {
- data <- data[, colNames] %>% rename(!(!(!colNames)))
+ data <- data %>% setDT() %>% setnames(old = colNames, new = names(colNames))
}
if (all(names(data) == c("mean", "sd", "autocorrelation")) ==
F) {
@@ -135,7 +135,7 @@ matrix_model <- function(data, initialPop, timesteps, covMatrix = NULL,
if (all(data$sd > 0) == F) {
stop("Invalid values in SD column")
}
- dat <- data %>% as_tibble()
+ dat <- setDT(data)
} else if (is.list(data) == T) {
if (length(data) > 3) {
stop("List data should only have 3 elements")
@@ -149,7 +149,7 @@ matrix_model <- function(data, initialPop, timesteps, covMatrix = NULL,
if (length(unique(map_int(data, length)))>1) {
stop("Matrices are not equal dimensions")
}
- dat <- tibble(mean = as.vector(t(data[[1]])), sd = as.vector(t(data[[2]])),
+ dat <- data.table(mean = as.vector(t(data[[1]])), sd = as.vector(t(data[[2]])),
autocorrelation = as.vector(t(data[[3]])))
} else {
stop("Invalid data type. Must be a list of three matrices or a data frame with three columns.")
@@ -166,31 +166,35 @@ matrix_model <- function(data, initialPop, timesteps, covMatrix = NULL,
if (is.null(repeatElements) == T) {
repeatElements <- matrix(seq(1:stages^2), ncol = stages, byrow = T)
}
- dat <- dat %>% mutate(dist = dists, zero = mean==0&sd==0,
- ref = as.vector(t(repeatElements)))
+ dat <- dat[, `:=`(dist = dists, zero = mean == 0 & sd == 0, ref = as.vector(t(repeatElements)))]
repeats <- repeatElements == matrix(seq(1:stages^2), ncol = stages, byrow = T)
# Create version of data that can be used to generate colored noise
- inputs <- dat %>% slice(which(t(repeats))) %>% filter(zero == F) %>%
- rowwise() %>% mutate(
- mean.trans = ifelse(mean == 0, 0, invoke(dist, list(mean))),
- sd.trans = ifelse(sd == 0, 0, variancefix(mean, sd, dist))
- )
+ unique <- dat[which(t(repeats))][zero == F]
+ unique$mean.trans <- map_dbl(c(1:nrow(unique)), function(x) {
+ if(dat[x,]$mean == 0) {0} else {
+ invoke(dat[x,]$dist, list(dat[x,]$mean))
+ }
+ })
+ unique$sd.trans <- map_dbl(c(1:nrow(unique)), function(x) {
+ if(dat[x,]$sd == 0) {0} else {
+ stdev_transform(dat[x,]$mean, dat[x,]$sd, dat[x,]$dist)
+ }
+ })
if (is.null(covMatrix) == T) {
- covMatrix <- cor2cov(inputs$sd, diag(nrow(inputs)))
+ covMatrix <- cor2cov(unique$sd, diag(nrow(unique)))
}
# Create colored noise, discard if invalid matrix
if(survivalOverflow == "redraw") {
repeat {
- inputs$noise <- colored_multi_rnorm(timesteps, inputs$mean.trans, inputs$sd.trans,
- inputs$autocorrelation, covMatrix) %>% split(col(.))
- result <- left_join(dat, inputs, by = c("mean", "sd", "autocorrelation", "dist", "zero", "ref"))
+ unique$noise <- colored_multi_rnorm(timesteps, unique$mean.trans, unique$sd.trans,
+ unique$autocorrelation, covMatrix) %>% split(col(.))
+ result <- dat[unique, on = .(mean, sd, autocorrelation, dist, zero, ref), allow.cartesian = TRUE]
result$noise[dat$zero==T] <- rep(list(rep.int(0, timesteps)), sum(dat$zero==T))
# checking for >1 probability
- result <- result %>% rowwise() %>% mutate(
- natural.noise = ifelse(zero == T, list(noise),
- ifelse(dist == "log", list(exp(noise)),
- list(plogis(noise))))
- )
+ result$natural.noise <- map(c(1:nrow(result)), function(x) {
+ if (result[x,]$zero) {result[x,]$noise} else if (result[x,]$dist=="log") {
+ exp(result[x,]$noise[[1]])} else {plogis(result[x,]$noise[[1]])}
+ })
matrices <- map(1:timesteps, function(x) {
matrix(map_dbl(result$natural.noise, x), byrow = T, ncol = stages)
})
@@ -201,15 +205,15 @@ matrix_model <- function(data, initialPop, timesteps, covMatrix = NULL,
}
}
} else if(survivalOverflow == "scale") {
- inputs$noise <- colored_multi_rnorm(timesteps, inputs$mean.trans, inputs$sd.trans,
- inputs$autocorrelation, covMatrix) %>% split(col(.))
- result <- left_join(dat, inputs, by = c("mean", "sd", "autocorrelation", "dist", "zero", "ref"))
+ unique$noise <- colored_multi_rnorm(timesteps, unique$mean.trans, unique$sd.trans,
+ unique$autocorrelation, covMatrix) %>% split(col(.))
+ result <- dat[unique, on = .(mean, sd, autocorrelation, dist, zero, ref), allow.cartesian = TRUE]
result$noise[dat$zero==T] <- rep(list(rep.int(0, timesteps)), sum(dat$zero==T))
# checking for >1 probability
- result <- result %>% rowwise() %>% mutate(
- natural.noise = ifelse(zero == T, list(noise),
- ifelse(dist == "log", list(exp(noise)),
- list(plogis(noise)))))
+ result$natural.noise <- map(c(1:nrow(result)), function(x) {
+ if (result[x,]$zero) {result[x,]$noise} else if (result[x,]$dist=="log") {
+ exp(result[x,]$noise[[1]])} else {plogis(result[x,]$noise[[1]])}
+ })
matrices <- map(1:timesteps, function(x) {
matrix(map_dbl(result$natural.noise, x), byrow = T, ncol = stages)
})
@@ -226,7 +230,9 @@ matrix_model <- function(data, initialPop, timesteps, covMatrix = NULL,
}
} else {stop("survivalOverflow must be set to 'redraw' or 'scale'")}
pop <- projection(initialPop, matrices)
- pop %>% map(as_tibble, .name_repair = ~ c(paste0("stage", 1:stages))) %>%
- bind_rows() %>% group_by(timestep = row_number()) %>% nest(data = -timestep) %>%
- mutate(total = map_dbl(data, sum)) %>% unnest(data)
+ # CONVERT TO DATA.TABLE
+ output <- pop %>% map(as.data.table) %>% rbindlist() %>%
+ .[, `:=`(total = rowSums(.SD), timestep = seq_len(.N))] %>% setcolorder("timestep")
+ names(output) <- c("timestep", map_chr(1:stages, ~paste0("stage", .)), "total")
+ return(output)
}
diff --git a/README.Rmd b/README.Rmd
index 035f166..2a563f4 100644
--- a/README.Rmd
+++ b/README.Rmd
@@ -11,13 +11,15 @@ knitr::opts_chunk$set(
fig.path = "man/figures/README-"
)
library(ggplot2)
+library(Rcpp)
```
-# colorednoise
+# colorednoise
[![Travis_build_status](https://travis-ci.org/japilo/colorednoise.svg?branch=master)](https://travis-ci.org/japilo/colorednoise)
[![CRAN_version](https://www.r-pkg.org/badges/version/colorednoise)](https://cran.r-project.org/package=colorednoise)
[![Coverage Status](https://img.shields.io/codecov/c/github/japilo/colorednoise/master.svg)](https://codecov.io/github/japilo/colorednoise?branch=master)
[![Download_count](https://cranlogs.r-pkg.org/badges/grand-total/colorednoise)](https://CRAN.R-project.org/package=colorednoise)
+[![Paper_doi](https://img.shields.io/badge/doi-10.1111/oik.06438-orange.svg)](https://doi.org/10.1111/oik.06438)
## Overview
diff --git a/README.md b/README.md
index 56b8c56..3d9f363 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,14 @@
-# colorednoise
+# colorednoise
[![Travis\_build\_status](https://travis-ci.org/japilo/colorednoise.svg?branch=master)](https://travis-ci.org/japilo/colorednoise)
[![CRAN\_version](https://www.r-pkg.org/badges/version/colorednoise)](https://cran.r-project.org/package=colorednoise)
[![Coverage
Status](https://img.shields.io/codecov/c/github/japilo/colorednoise/master.svg)](https://codecov.io/github/japilo/colorednoise?branch=master)
[![Download\_count](https://cranlogs.r-pkg.org/badges/grand-total/colorednoise)](https://CRAN.R-project.org/package=colorednoise)
+[![Paper\_doi](https://img.shields.io/badge/doi-10.1111/oik.06438-orange.svg)](https://doi.org/10.1111/oik.06438)
## Overview
diff --git a/cran-comments.md b/cran-comments.md
index dd8d2a8..39bc97e 100644
--- a/cran-comments.md
+++ b/cran-comments.md
@@ -1,7 +1,7 @@
## Test environments
-* local OS X install, R 3.6
-* Ubuntu 16.04 (on travis-ci), R 3.5, 3.6, devel
-* win-builder, R devel
+* local Windows 10 install, R 4.0
+* Ubuntu 16.04 (on travis-ci), R 3.6, 4.0, devel
+* macOS 10.13 (on travis-ci), R 3.6, 4.0, devel
## R CMD check results
diff --git a/man/autocorr_sim.Rd b/man/autocorr_sim.Rd
index 442e1f3..6838eda 100644
--- a/man/autocorr_sim.Rd
+++ b/man/autocorr_sim.Rd
@@ -5,8 +5,17 @@
\title{Simulate Temporally Autocorrelated Populations for Every Combination of
Parameters}
\usage{
-autocorr_sim(timesteps, start, survPhi, fecundPhi, survMean, survSd,
- fecundMean, fecundSd, replicates)
+autocorr_sim(
+ timesteps,
+ start,
+ survPhi,
+ fecundPhi,
+ survMean,
+ survSd,
+ fecundMean,
+ fecundSd,
+ replicates
+)
}
\arguments{
\item{timesteps}{The number of timesteps you want to simulate. Individuals
diff --git a/man/colored_multi_rnorm.Rd b/man/colored_multi_rnorm.Rd
index d04433b..3666c0f 100644
--- a/man/colored_multi_rnorm.Rd
+++ b/man/colored_multi_rnorm.Rd
@@ -25,9 +25,12 @@ A matrix with as many rows as timesteps and as many columns as mu/sigma/phi valu
Generates random variables that are correlated to each other and temporally autocorrelated.
}
\examples{
-cov <- matrix(c(0.037, 0.044, -0.048, 0.044, 0.247, -0.008, -0.047, -0.008, 0.074), nrow = 3)
+cov <- matrix(c(1, 0.53, 0.73, 0.53, 1, 0.44, 0.73, 0.44, 1), nrow = 3)
test <- colored_multi_rnorm(100, c(0, 3, 5), c(1, 0.5, 1), c(0.5, -0.3, 0), cov)
var(test)
-library(dplyr)
-test \%>\% as.data.frame() \%>\% summarize_all(.funs = c("mean", "sd", "autocorrelation"))
+library(data.table)
+as.data.table(test)[, .(V1_mean = mean(V1), V2_mean = mean(V2), V3_mean = mean(V3),
+V1_sd = sd(V1), V2_sd = sd(V2), V3_sd = sd(V3),
+V1_autocorrelation = autocorrelation(V1), V2_autocorrelation = autocorrelation(V2),
+V3_autocorrelation = autocorrelation(V3))]
}
diff --git a/man/colorednoise.Rd b/man/colorednoise.Rd
index e3e1f7c..e787019 100644
--- a/man/colorednoise.Rd
+++ b/man/colorednoise.Rd
@@ -3,7 +3,6 @@
\docType{package}
\name{colorednoise}
\alias{colorednoise}
-\alias{colorednoise-package}
\title{\code{colorednoise} package}
\description{
Simulate Temporally Autocorrelated Populations
diff --git a/man/figures/README-example-1.png b/man/figures/README-example-1.png
index fe73f2a..b629885 100644
Binary files a/man/figures/README-example-1.png and b/man/figures/README-example-1.png differ
diff --git a/man/figures/README-example-2.png b/man/figures/README-example-2.png
index d3f7159..4d3a3b5 100644
Binary files a/man/figures/README-example-2.png and b/man/figures/README-example-2.png differ
diff --git a/man/figures/hex.png b/man/figures/hex.png
new file mode 100644
index 0000000..d9cc1db
Binary files /dev/null and b/man/figures/hex.png differ
diff --git a/man/figures/logo.png b/man/figures/logo.png
deleted file mode 100644
index 4bec35e..0000000
Binary files a/man/figures/logo.png and /dev/null differ
diff --git a/man/matrix_model.Rd b/man/matrix_model.Rd
index 725ee91..f9fc49e 100644
--- a/man/matrix_model.Rd
+++ b/man/matrix_model.Rd
@@ -4,9 +4,16 @@
\alias{matrix_model}
\title{Temporally Autocorrelated Matrix Population Models}
\usage{
-matrix_model(data, initialPop, timesteps, covMatrix = NULL,
- colNames = NULL, matrixStructure = NULL, repeatElements = NULL,
- survivalOverflow = "scale")
+matrix_model(
+ data,
+ initialPop,
+ timesteps,
+ covMatrix = NULL,
+ colNames = NULL,
+ matrixStructure = NULL,
+ repeatElements = NULL,
+ survivalOverflow = "scale"
+)
}
\arguments{
\item{data}{The input data can be one of two formats: a list of three matrices, or a data frame
diff --git a/man/stdev_transform.Rd b/man/stdev_transform.Rd
new file mode 100644
index 0000000..6a7a1fe
--- /dev/null
+++ b/man/stdev_transform.Rd
@@ -0,0 +1,34 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/RcppExports.R
+\name{stdev_transform}
+\alias{stdev_transform}
+\title{Translate Standard Deviation from the Natural Scale to the Log or Logit Scale}
+\usage{
+stdev_transform(mu, sigma, dist)
+}
+\arguments{
+\item{mu}{The mean of the distribution on the natural scale.}
+
+\item{sigma}{The standard devation of the distribution on the natural scale.}
+
+\item{dist}{The distribution to which the standard deviation should be transformed.}
+}
+\value{
+The standard deviation translated to the log or logit scale.
+}
+\description{
+This function changes a given standard deviation so that when a vector of samples is drawn from the given distribution,
+the original standard deviation will be recovered once it is back-transformed from the log or logit scale. In effect,
+the function "translates" a standard deviation from the natural scale to the log or logit scale for the purposes of
+random draws from a probability distribution.
+}
+\examples{
+mean <- 10
+stdev <- 2
+mean_trans <- log(mean)
+stdev_trans <- stdev_transform(mean, stdev, "log")
+draws <- rnorm(50, mean_trans, stdev_trans)
+natural_scale <- exp(draws)
+mean(draws)
+sd(draws)
+}
diff --git a/man/unstructured_pop.Rd b/man/unstructured_pop.Rd
index 448052b..8920246 100644
--- a/man/unstructured_pop.Rd
+++ b/man/unstructured_pop.Rd
@@ -4,8 +4,16 @@
\alias{unstructured_pop}
\title{Simulated Time Series of an Unstructured Temporally Autocorrelated Population}
\usage{
-unstructured_pop(start, timesteps, survPhi, fecundPhi, survMean, survSd,
- fecundMean, fecundSd)
+unstructured_pop(
+ start,
+ timesteps,
+ survPhi,
+ fecundPhi,
+ survMean,
+ survSd,
+ fecundMean,
+ fecundSd
+)
}
\arguments{
\item{start}{The starting population size.}
diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp
index c9787a8..6759c61 100644
--- a/src/RcppExports.cpp
+++ b/src/RcppExports.cpp
@@ -60,16 +60,16 @@ BEGIN_RCPP
return rcpp_result_gen;
END_RCPP
}
-// variancefix
-double variancefix(double mu, double sigma, std::string dist);
-RcppExport SEXP _colorednoise_variancefix(SEXP muSEXP, SEXP sigmaSEXP, SEXP distSEXP) {
+// stdev_transform
+double stdev_transform(double mu, double sigma, std::string dist);
+RcppExport SEXP _colorednoise_stdev_transform(SEXP muSEXP, SEXP sigmaSEXP, SEXP distSEXP) {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Rcpp::RNGScope rcpp_rngScope_gen;
Rcpp::traits::input_parameter< double >::type mu(muSEXP);
Rcpp::traits::input_parameter< double >::type sigma(sigmaSEXP);
Rcpp::traits::input_parameter< std::string >::type dist(distSEXP);
- rcpp_result_gen = Rcpp::wrap(variancefix(mu, sigma, dist));
+ rcpp_result_gen = Rcpp::wrap(stdev_transform(mu, sigma, dist));
return rcpp_result_gen;
END_RCPP
}
@@ -109,7 +109,7 @@ static const R_CallMethodDef CallEntries[] = {
{"_colorednoise_multi_rnorm", (DL_FUNC) &_colorednoise_multi_rnorm, 3},
{"_colorednoise_cor2cov", (DL_FUNC) &_colorednoise_cor2cov, 2},
{"_colorednoise_colored_multi_rnorm", (DL_FUNC) &_colorednoise_colored_multi_rnorm, 5},
- {"_colorednoise_variancefix", (DL_FUNC) &_colorednoise_variancefix, 3},
+ {"_colorednoise_stdev_transform", (DL_FUNC) &_colorednoise_stdev_transform, 3},
{"_colorednoise_unstructured_pop", (DL_FUNC) &_colorednoise_unstructured_pop, 8},
{"_colorednoise_projection", (DL_FUNC) &_colorednoise_projection, 2},
{NULL, NULL, 0}
diff --git a/src/noise.cpp b/src/noise.cpp
index 60837b0..6ab90e2 100644
--- a/src/noise.cpp
+++ b/src/noise.cpp
@@ -85,11 +85,14 @@ arma::mat cor2cov(Rcpp::NumericVector sigma, Rcpp::NumericMatrix corrMatrix) {
//' @param covMatrix A valid covariance matrix. The number of rows/columns must match the length of the mu, sigma, and phi vectors.
//' @return A matrix with as many rows as timesteps and as many columns as mu/sigma/phi values.
//' @examples
-//' cov <- matrix(c(0.037, 0.044, -0.048, 0.044, 0.247, -0.008, -0.047, -0.008, 0.074), nrow = 3)
+//' cov <- matrix(c(1, 0.53, 0.73, 0.53, 1, 0.44, 0.73, 0.44, 1), nrow = 3)
//' test <- colored_multi_rnorm(100, c(0, 3, 5), c(1, 0.5, 1), c(0.5, -0.3, 0), cov)
//' var(test)
-//' library(dplyr)
-//' test %>% as.data.frame() %>% summarize_all(.funs = c("mean", "sd", "autocorrelation"))
+//' library(data.table)
+//' as.data.table(test)[, .(V1_mean = mean(V1), V2_mean = mean(V2), V3_mean = mean(V3),
+//' V1_sd = sd(V1), V2_sd = sd(V2), V3_sd = sd(V3),
+//' V1_autocorrelation = autocorrelation(V1), V2_autocorrelation = autocorrelation(V2),
+//' V3_autocorrelation = autocorrelation(V3))]
//' @export
// [[Rcpp::export]]
Rcpp::NumericMatrix colored_multi_rnorm(int timesteps, Rcpp::NumericVector mean, Rcpp::NumericVector sd, Rcpp::NumericVector phi, Rcpp::NumericMatrix covMatrix) {
diff --git a/src/simulation.cpp b/src/simulation.cpp
index dfcdf33..1e5e6e1 100644
--- a/src/simulation.cpp
+++ b/src/simulation.cpp
@@ -2,12 +2,28 @@
#include "noise.h"
// [[Rcpp::depends(RcppArmadillo)]]
-// Variance Fix
-//
-// This function changes the variance so that once it is back-transformed
-// from the logit scale, the original variance is recovered.
+//' Translate Standard Deviation from the Natural Scale to the Log or Logit Scale
+//'
+//' This function changes a given standard deviation so that when a vector of samples is drawn from the given distribution,
+//' the original standard deviation will be recovered once it is back-transformed from the log or logit scale. In effect,
+//' the function "translates" a standard deviation from the natural scale to the log or logit scale for the purposes of
+//' random draws from a probability distribution.
+//' @param mu The mean of the distribution on the natural scale.
+//' @param sigma The standard devation of the distribution on the natural scale.
+//' @param dist The distribution to which the standard deviation should be transformed.
+//' @return The standard deviation translated to the log or logit scale.
+//' @examples
+//' mean <- 10
+//' stdev <- 2
+//' mean_trans <- log(mean)
+//' stdev_trans <- stdev_transform(mean, stdev, "log")
+//' draws <- rnorm(50, mean_trans, stdev_trans)
+//' natural_scale <- exp(draws)
+//' mean(draws)
+//' sd(draws)
+//' @export
// [[Rcpp::export]]
-double variancefix(double mu, double sigma, std::string dist){
+double stdev_transform(double mu, double sigma, std::string dist){
if (sigma == 0) {
return 0;
}
@@ -68,11 +84,11 @@ double variancefix(double mu, double sigma, std::string dist){
Rcpp::DataFrame unstructured_pop(int start, int timesteps, double survPhi, double fecundPhi, double survMean, double survSd, double fecundMean, double fecundSd) {
// These lines generate the temporally autocorrelated random numbers
double survmu = R::qlogis(survMean, 0, 1, true, false);
- double survsigma = variancefix(survMean, survSd, "qlogis");
+ double survsigma = stdev_transform(survMean, survSd, "qlogis");
Rcpp::NumericVector survnoise = colored_noise(timesteps, survmu, survsigma, survPhi);
Rcpp::NumericVector St = plogis(survnoise);
double fecundmu = log(fecundMean);
- double fecundsigma = variancefix(fecundMean, fecundSd, "log");
+ double fecundsigma = stdev_transform(fecundMean, fecundSd, "log");
Rcpp::NumericVector fecundnoise = colored_noise(timesteps, fecundmu, fecundsigma, fecundPhi);
Rcpp::NumericVector Ft = exp(fecundnoise);
// This loop kills some individuals according to St probabilities, creates
diff --git a/tests/testthat/test_noise.R b/tests/testthat/test_noise.R
index 353e632..a6f8da2 100644
--- a/tests/testthat/test_noise.R
+++ b/tests/testthat/test_noise.R
@@ -1,6 +1,6 @@
library(colorednoise)
library(purrr)
-library(dplyr)
+library(data.table)
context("Autocorrelation of colored noise")
test_that("colored noise can produce blue noise", {
@@ -27,7 +27,9 @@ test_that("colored_multi_rnorm can produce red noise", {
set.seed(989)
corr <- matrix(c(1, 0.53, 0.73, 0.53, 1, 0.44, 0.73, 0.44, 1), nrow = 3)
test <- colored_multi_rnorm(100, c(0, 3, 5), c(1, 0.5, 1), c(0.5, 0.5, 0.5), corr) %>%
- as_tibble() %>% summarise_all(autocorrelation) %>% as.numeric()
+ as.data.table() %>%
+ .[, .(V1_autocorr = autocorrelation(V1), V2_autocorr = autocorrelation(V2), V3_autocorr = autocorrelation(V3))] %>%
+ as.numeric()
expect_true(all(test > 0.5)==T)
})
@@ -35,6 +37,8 @@ test_that("colored_multi_rnorm can produce blue noise", {
set.seed(19045)
corr <- matrix(c(1, 0.53, 0.73, 0.53, 1, 0.44, 0.73, 0.44, 1), nrow = 3)
test <- colored_multi_rnorm(100, c(0, 3, 5), c(1, 0.5, 1), c(-0.5, -0.5, -0.5), corr) %>%
- as_tibble() %>% summarise_all(autocorrelation) %>% as.numeric()
+ as.data.table() %>%
+ .[, .(V1_autocorr = autocorrelation(V1), V2_autocorr = autocorrelation(V2), V3_autocorr = autocorrelation(V3))] %>%
+ as.numeric()
expect_true(all(test < -0.4)==T)
})
diff --git a/tests/testthat/test_simulations.R b/tests/testthat/test_simulations.R
index acb027f..76b96e4 100644
--- a/tests/testthat/test_simulations.R
+++ b/tests/testthat/test_simulations.R
@@ -1,20 +1,22 @@
library(purrr)
-library(dplyr)
+library(data.table)
context("Consistency in population simulations")
test_that("unstructured_pop can produce blue noise populations", {
test_blue <- rerun(.n = 1000, unstructured_pop(start = 5000, timesteps = 50,
survPhi = -0.5, survMean = 0.4, survSd = 0.05, fecundPhi = 0,
- fecundMean = 1.5, fecundSd = 0.2)) %>% map(~mutate(., est_surv = survivors/population,
- est_fecund = newborns/survivors)) %>% map_dbl(~autocorrelation(.$est_surv))
+ fecundMean = 1.5, fecundSd = 0.2)) %>% map(setDT) %>%
+ map(~.[, `:=`(est_surv = survivors/population, est_fecund = newborns/survivors)]) %>%
+ map_dbl(~autocorrelation(.$est_surv))
expect_true(mean(test_blue) < -0.2)
})
test_that("unstructured_pop can produce red noise populations", {
test_red <- rerun(.n = 1000, unstructured_pop(start = 5000, timesteps = 50,
survPhi = 0.5, survMean = 0.4, survSd = 0.05, fecundPhi = 0,
- fecundMean = 1.5, fecundSd = 0.2)) %>% map(~mutate(., est_surv = survivors/population,
- est_fecund = newborns/survivors)) %>% map_dbl(~autocorrelation(.$est_surv))
+ fecundMean = 1.5, fecundSd = 0.2)) %>% map(setDT) %>%
+ map(~.[, `:=`(est_surv = survivors/population, est_fecund = newborns/survivors)]) %>%
+ map_dbl(~autocorrelation(.$est_surv))
expect_true(mean(test_red) > 0.2)
})
@@ -33,11 +35,11 @@ test_that("matrix_model can produce cross-correlated autocorrelated populations
expect_true(sum(test[nrow(test), 2:3]) > sum(test[1, 2:3]))
})
-test_that("output of variancefix transforms back to the natural scale", {
+test_that("output of stdev_transform transforms back to the natural scale", {
mu <- 0.5
sigma <- 0.2
mu.log <- log(mu)
- sigma.log <- variancefix(mu, sigma, "log")
+ sigma.log <- stdev_transform(mu, sigma, "log")
rand <- rnorm(1000, mu.log, sigma.log) %>% exp()
expect_true(sd(rand)>=sigma && sd(rand)<0.25)
})
diff --git a/vignettes/noise.Rmd b/vignettes/noise.Rmd
index 8c6b860..3182f1c 100644
--- a/vignettes/noise.Rmd
+++ b/vignettes/noise.Rmd
@@ -15,9 +15,10 @@ knitr::opts_chunk$set(
comment = "#>"
)
library("colorednoise")
-library("dplyr")
library("ggplot2")
library("purrr")
+library("data.table")
+library("Rcpp")
```
## What is colored noise?
@@ -65,9 +66,9 @@ The estimates for these seem to be quite accurate. But let's try generating a wh
```{r generate replicates}
raw_sims <- cross_df(list(timesteps = 20, phi = c(-0.5, 0, 0.5), mean = 0.3, sd = c(0.5, 0.7, 0.9, 1.1, 1.3, 1.5))) %>% rerun(.n = 30, pmap(., colored_noise))
-labels <- raw_sims %>% map(1) %>% bind_rows()
+labels <- raw_sims %>% map(1) %>% rbindlist()
noise <- raw_sims %>% map(2) %>% flatten()
-estimates <- data.frame(mu = map_dbl(noise, mean), sigma = map_dbl(noise, sd), autocorrelation = map_dbl(noise, autocorrelation))
+estimates <- data.table(mu = map_dbl(noise, mean), sigma = map_dbl(noise, sd), autocorrelation = map_dbl(noise, autocorrelation))
sd_range <- cbind(labels, estimates)
head(sd_range)
```
@@ -75,9 +76,12 @@ head(sd_range)
We can visualize these results by finding the mean and confidence intervals of the autocorrelation estimates for each combination of variance and noise color, and plotting them out.
```{r plot CIs}
-sd_range %>% group_by(phi, sd) %>% summarize_at(funs(lower.ci = ((function(bar){quantile(bar, probs=c(0.05, 0.95))[[1]]})(.)),
- upper.ci = ((function(bar){quantile(bar, probs=c(0.05, 0.95))[[2]]})(.)),
- mean = mean(.)), .vars = vars(autocorrelation)) -> summ
+summ <- sd_range[, .(lower.ci = ((function(bar) {
+ quantile(bar, probs = c(0.05, 0.95))[[1]]
+})(autocorrelation)), upper.ci = ((function(bar) {
+ quantile(bar, probs = c(0.05, 0.95))[[2]]
+})(autocorrelation)), mean = mean(autocorrelation)), keyby = .(phi,
+ sd)]
ggplot(summ, aes(x = sd, y = mean)) +
geom_pointrange(aes(ymin = lower.ci, ymax = upper.ci, color = factor(phi)), size = 0.8) +
geom_hline(yintercept = 0, linetype = 2, color = "#C0C0C0") +
@@ -114,15 +118,17 @@ Here we see one example of a population simulated by the function.
Now let's estimate the autocorrelation in each of these simulated populations. There is a utility function `autocorrelation` in this package that measures temporal autocorrelation at a time lag of 1.
```{r estimate autocorrelation}
-sims %>% map(~group_by(., survPhi, timesteps)) %>% map(~summarize(., acf.surv = autocorrelation(est_surv, biasCorrection = F))) %>% bind_rows -> estimates
+estimates <- sims %>% map(~.[, .(acf.surv = autocorrelation(est_surv, biasCorrection = F)), keyby = .(survPhi, timesteps)]) %>% rbindlist()
```
I find that this format of ggplot displays the estimates by noise color very nicely.
```{r plotting estimates, fig.height=5, fig.width=8}
-estimates %>% group_by(survPhi, timesteps) %>% summarize_at(funs(lower.ci = ((function(bar){quantile(bar, probs=c(0.05, 0.95), na.rm = T)[[1]]})(.)),
- upper.ci = ((function(bar){quantile(bar, probs=c(0.05, 0.95), na.rm = T)[[2]]})(.)),
- mean = mean(., na.rm = T)), .vars = vars(acf.surv)) -> summ2
+summ2 <- estimates[, .(lower.ci = ((function(bar) {
+ quantile(bar, probs = c(0.05, 0.95))[[1]]
+})(acf.surv)), upper.ci = ((function(bar) {
+ quantile(bar, probs = c(0.05, 0.95))[[2]]
+})(acf.surv)), mean = mean(acf.surv)), keyby = .(survPhi, timesteps)]
# Noise color values for the graph in hexadecimal
noise = c("#0033FF", "#3366FF", "#6699FF", "#99CCFF", "#FFFFFF", "#FF9999", "#FF6666","#FF0000", "#CC0000")
ggplot(summ2, aes(x=timesteps, y=mean)) + geom_point(size=8, aes(color=factor(survPhi))) +
@@ -145,9 +151,11 @@ where \phi is the autocorrelation and T is the length of the time series.
Here is what the autocorrelation estimates look like when I turn on the bias correction in the autocorrelation function.
```{r bias correction, message = F}
-sims %>% map(~group_by(., survPhi, timesteps)) %>% map(~summarize(., acf.surv = autocorrelation(est_surv, biasCorrection = TRUE))) %>% bind_rows() %>% group_by(survPhi, timesteps) %>% summarize_at(funs(lower.ci = ((function(bar){quantile(bar, probs=c(0.05, 0.95), na.rm = T)[[1]]})(.)),
- upper.ci = ((function(bar){quantile(bar, probs=c(0.05, 0.95), na.rm = T)[[2]]})(.)),
- mean = mean(., na.rm = T)), .vars = vars(acf.surv)) -> summ3
+summ3 <- sims %>% map(~.[, .(acf.surv = autocorrelation(est_surv, biasCorrection = TRUE)), keyby = .(survPhi, timesteps)]) %>% rbindlist() %>% .[, .(lower.ci = ((function(bar) {
+ quantile(bar, probs = c(0.05, 0.95), na.rm=T)[[1]]
+})(acf.surv)), upper.ci = ((function(bar) {
+ quantile(bar, probs = c(0.05, 0.95), na.rm=T)[[2]]
+})(acf.surv)), mean = mean(acf.surv)), keyby = .(survPhi, timesteps)]
ggplot(summ3, aes(x=timesteps, y=mean)) +
geom_point(size=8, aes(color=factor(survPhi))) +
geom_pointrange(aes(ymin=lower.ci, ymax=upper.ci), size=0.8) +