Skip to content

Commit 0ae8a40

Browse files
committed
asPoisson WIP - needs rethink
1 parent 1a71add commit 0ae8a40

4 files changed

Lines changed: 102 additions & 32 deletions

File tree

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export(aa)
1414
export(addSegSite)
1515
export(asCategorical)
1616
export(asLogNormal)
17+
export(asPoisson)
1718
export(attrition)
1819
export(bv)
1920
export(cChr)

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# AlphaSimR 2.2.0
22

3+
* Added asPoisson() function.
4+
35
* Added asLogNormal() function.
46

57
* Improved examples for asCategorical() function.

R/phenotypes.R

Lines changed: 60 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -557,47 +557,75 @@ asCategorical = function(x, p = NULL, mean = 0, var = 1,
557557

558558
#' @title Convert a normal (Gaussian) trait to a count (Poisson) trait
559559
#' @param x matrix, values for one or more traits (if not a matrix,
560-
#' we cast to a matrix)
561-
#' @param TODO numeric or list, when numeric, provide a vector of TODO
560+
#' we cast to a matrix).
561+
#' @param intercept \code{NULL}, numeric or list, trait intercept(s) on the log
562+
#' scale; when \code{NULL} an intercept of 0 is assumed, when numeric
563+
#' intercepts for all traits in \code{x} must be provided, and when list
564+
#' intercepts for all traits in \code{x} must be provided with the possibility
565+
#' to pass a \code{NULL} list node to skip the conversion for a trait
566+
#' (see examples).
562567
#' @return matrix of values with some traits recoded as counts
563568
#' @details If input trait is normal (Gaussian) then this function generates a
564-
#' count trait according to the Poisson generalised linear model.
569+
#' count trait according to the Poisson generalised linear model. Count values
570+
#' are drawn from a Poisson distribution with rate
571+
#' \code{exp(intercept + x)}.
565572
#' @examples
573+
#' #Simulate a founder pop, set latent trait parameters, and create a population
566574
#' founderPop = quickHaplo(nInd=20, nChr=1, segSites=10)
567575
#' SP = SimParam$new(founderPop)
568576
#' \dontshow{SP$nThreads = 1L}
569-
#' SP$addTraitA(nQtlPerChr = 10, mean = c(0, 0), var = c(1, 2),
577+
#' trtMeanLog = c(0, 0)
578+
#' trtVarGLog = c(1, 2)
579+
#' SP$addTraitA(nQtlPerChr = 10, mean = trtMeanLog, var = trtVarGLog,
570580
#' corA = matrix(data = c(1.0, 0.6,
571581
#' 0.6, 1.0), ncol = 2))
582+
#' trtVarELog = c(1, 1)
583+
#' trtVarPLog = trtVarGLog + trtVarELog
584+
#' SP$setVarE(varE = trtVarELog)
572585
#' pop = newPop(founderPop)
573-
#' pop = setPheno(pop, varE = c(1, 1))
574586
#' pheno(pop)
587+
#'
575588
#' #Convert a single input trait
576-
#' asCount(x = pheno(pop)[, 2])
577-
#' asCount(x = pheno(pop)[, 2], TODO = c(-1, 0, 1))
578-
#' asCount(x = pheno(pop)[, 2], TODO = c(-Inf, -1, 0, 1, Inf))
589+
#' asPoisson(x = pheno(pop)[, 1])
590+
#' asPoisson(x = pheno(pop)[, 2], intercept = -trtVarPLog[2]/2)
591+
#'
579592
#' #Convert multiple input traits
580-
#' try(asCount(x = pheno(pop)))
581-
#' asCount(x = pheno(pop),
582-
#' TODO = list(NULL,
583-
#' ???))
584-
#' TODO export
585-
# asCount = function(x, TODO = 10) {
586-
# if (!is.matrix(x)) {
587-
# x = as.matrix(x)
588-
# }
589-
# nTraits = ncol(x)
590-
# if (is.numeric(TODO)) {
591-
# if (nTraits > 1) {
592-
# stop("When x contains more than one column, you must supply a list of TODO! See examples.")
593-
# }
594-
# TODO = list(TODO)
595-
# }
596-
# for (trt in 1:nTraits) {
597-
# if (!is.null(TODO[[trt]])) {
598-
# TODO: need to think what to do with an intercept and lambda
599-
# x[, trt] = round(exp(x[, trt]))
600-
# }
601-
# }
602-
# return(x)
603-
# }
593+
#' try(asPoisson(x = pheno(pop), intercept = 0))
594+
#' asPoisson(x = pheno(pop), intercept = c(0, -trtVarPLog[2]/2))
595+
#' asPoisson(x = pheno(pop), intercept = list(0, NULL))
596+
#'
597+
#' #Store the recoded trait manually
598+
#' pheno(pop)
599+
#' pop@pheno[, 1] = asPoisson(x = pheno(pop)[, 1])
600+
#' pheno(pop)
601+
#' @export
602+
asPoisson <- function(x, intercept = NULL) {
603+
stop("Come back to this - we need to rethink intercept vs lambda and VarE on latent scale vs variance from Poisson process itself!")
604+
if (!is.matrix(x)) {
605+
x = as.matrix(x)
606+
}
607+
nTraits = ncol(x)
608+
if (is.null(intercept)) {
609+
intercept = rep(x = 0, times = nTraits)
610+
}
611+
if (is.numeric(intercept)) {
612+
if (length(intercept) != nTraits) {
613+
stop("You must supply intercept for all traits in x!")
614+
}
615+
for (trt in 1:nTraits) {
616+
x[, trt] = rpois(n = nrow(x), lambda = exp(intercept[trt] + x[, trt]))
617+
}
618+
} else if (is.list(intercept)) {
619+
if (length(intercept) != nTraits) {
620+
stop("You must supply intercept for all traits in x!")
621+
}
622+
for (trt in 1:nTraits) {
623+
if (!is.null(intercept[[trt]])) {
624+
x[, trt] = rpois(n = nrow(x), lambda = exp(intercept[[trt]] + x[, trt]))
625+
}
626+
}
627+
} else {
628+
stop("intercept must be NULL, numeric, or list!")
629+
}
630+
return(x)
631+
}

tests/testthat/test-phenotypes.R

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,45 @@ test_that("asCategorical_converts_correctly", {
8585
expect_equal(cont2, cont2Exp)
8686
})
8787

88+
test_that("asPoisson_converts_correctly", {
89+
cont = matrix(data = c(-1, 0, 1, 0, 1, 2), nrow = 3, ncol = 2)
90+
91+
set.seed(100)
92+
expSingle = matrix(rpois(n = nrow(cont), lambda = exp(cont[, 1])))
93+
set.seed(100)
94+
expect_equal(asPoisson(x = cont[, 1]), expSingle)
95+
96+
set.seed(101)
97+
expShift = matrix(rpois(n = nrow(cont), lambda = exp(log(2) + cont[, 1])))
98+
set.seed(101)
99+
expect_equal(asPoisson(x = cont[, 1], intercept = log(2)), expShift)
100+
101+
set.seed(102)
102+
expMulti = cbind(
103+
rpois(n = nrow(cont), lambda = exp(cont[, 1])),
104+
rpois(n = nrow(cont), lambda = exp(log(3) + cont[, 2]))
105+
)
106+
set.seed(102)
107+
expect_equal(
108+
asPoisson(x = cont, intercept = c(0, log(3))),
109+
expMulti
110+
)
111+
112+
set.seed(103)
113+
expPartial = cbind(
114+
cont[, 1],
115+
rpois(n = nrow(cont), lambda = exp(log(3) + cont[, 2]))
116+
)
117+
set.seed(103)
118+
expect_equal(
119+
asPoisson(x = cont, intercept = list(NULL, log(3))),
120+
expPartial
121+
)
122+
123+
expect_error(asPoisson(x = cont, intercept = 0))
124+
expect_error(asPoisson(x = cont, intercept = TRUE))
125+
})
126+
88127
test_that("pop@gv and genParam(pop)@gv match", {
89128
# This test is here since we have two different code paths for these two
90129
# functionalities and we had one bug in one code path

0 commit comments

Comments
 (0)