Skip to content

Commit

Permalink
Updating addPeriods
Browse files Browse the repository at this point in the history
  • Loading branch information
Keith Goldfeld committed Apr 12, 2024
1 parent 8d1fd44 commit e21cb03
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 26 deletions.
4 changes: 2 additions & 2 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# simstudy (development version)

## New features
*`addPeriods` has a new argument `periodVec` that allows user to specify
specific measurement time periods as a vector.
*`addPeriods` now includes a new argument `periodVec` that allows users to designate
specific measurement time periods using vector.

## Minor fix
* Function `logisticCoefs` now correctly handles double dot notation.
Expand Down
38 changes: 20 additions & 18 deletions R/group_data.R
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,25 @@
#' @param timevarName Name of new time dependent variable
#' @param timeid Variable name for new index field. Defaults to "timevar"
#' @param perName Variable name for period field. Defaults to "period"
#' @param perVec Vector of period times. Defaults to NULL
#' @param periodVec Vector of period times. Defaults to NULL
#' @details It is possible to generate longitudinal data with varying
#' numbers of measurement periods as well as varying time intervals between
#' each measurement period. This is done by defining specific variables \emph{in} the
#' data set that define the number of observations per subject and the average
#' interval time between each observation. \bold{\emph{nCount}} defines the number of
#' measurements for an individual; \bold{\emph{mInterval}} specifies the average time between
#' intervals for a subject; and vInterval specifies the variance of those
#' interval times. If \bold{\emph{vInterval}} is set to 0 or is not defined, the interval for
#' intervals for a subject; and \bold{\emph{vInterval}} specifies the variance of those
#' interval times. If \bold{\emph{mInterval}} is not defined, no intervals are used. If \bold{\emph{vInterval}} is set to 0 or is not defined, the interval for
#' a subject is determined entirely by the mean interval. If \bold{\emph{vInterval}} is
#' greater than 0, time intervals are generated using a gamma distribution
#' with specified mean and dispersion. If either \bold{\emph{nPeriods}} or \bold{\emph{timevars}}
#' is specified, that will override any \bold{\emph{nCount}}, \bold{\emph{mInterval}}, and
#' \bold{\emph{vInterval}} data.
#'
#' \bold\emph{{perVec}} is used to specify measurement periods that are different
#' the default counting variables. If \bold\emph{{perVec}} is not specified,
#' \bold{\emph{periodVec}} is used to specify measurement periods that are different
#' the default counting variables. If \bold{\emph{periodVec}} is not specified,
#' the periods default to \emph{0, 1, ... n-1}, with \emph{n} periods. If
#' \bold\emph{{perVec}} is specified as \emph{c(x_1, x_2, ... x_n)}, then
#' \bold{\emph{periodVec}} is specified as \emph{c(x_1, x_2, ... x_n)}, then
#' \emph{x_1, x_2, ... x_n} represent the measurement periods.
#' @return An updated data.table that that has multiple rows
#' per observation in dtName
Expand Down Expand Up @@ -98,10 +98,13 @@ addPeriods <- function(dtName,
if (!is.null(nPeriods)) { # same number for each subject

dtTimes1 <- dtX1[, list(.period = (0:(nPeriods - 1))), keyby = idvars]

} else {

if ("nCount" %in% names(dtX1)) { # specified for each subject

dtTimes1 <- dtX1[, list(.period = (0:(nCount - 1))), keyby = idvars]

} else { # not specified for each subject or for all

stop("No period or count parameter provided")
Expand All @@ -113,6 +116,12 @@ addPeriods <- function(dtName,
data.table::setkeyv(dtX1, idvars)
dtTimes1 <- dtTimes1[dtX1]
data.table::setkeyv(dtTimes1, c(idvars, ".period"))

# Remove nCount if it was included

if ("nCount" %in% names(dtX1)) {
dtTimes1[, nCount := NULL]
}

# Create code for final index assignment

Expand Down Expand Up @@ -152,14 +161,11 @@ addPeriods <- function(dtName,
eval(cmd)
data.table::setkeyv(dtTimes1, timeid)

data.table::setnames(dtTimes1, old = ".period", new = perName)

} else { # if time dependent variables not specified

eval(cmd)
data.table::setkeyv(dtTimes1, timeid)

data.table::setnames(dtTimes1, old = ".period", new = perName)
}

# if specified different measurement intervals:
Expand All @@ -169,30 +175,26 @@ addPeriods <- function(dtName,
assertNumeric(periodVec = periodVec)
assertLength(periodVec = periodVec, length = nPeriods) # Need to make sure

dtTimes1[, period := periodVec[period + 1]]
dtTimes1[, .period := periodVec[.period + 1]]
}

} else { # is.null(nPeriods) == TRUE

if (all(c("nCount", "mInterval") %in% names(dtX1))) {
if ( "mInterval" %in% names(dtX1) ) {
if (!("vInterval" %in% names(dtX1))) dtTimes1[, vInterval := 0]

dtTimes1[, timeElapsed := .genPosSkew(1, mInterval, vInterval), keyby = c(idvars, ".period")]
dtTimes1[.period == 0, timeElapsed := 0]

dtTimes1[, time := round(cumsum(timeElapsed)), keyby = idvars]
dtTimes1[, c("timeElapsed", "nCount", "mInterval", "vInterval") := NULL]
dtTimes1[, c("timeElapsed", "mInterval", "vInterval") := NULL]

eval(cmd)
data.table::setkeyv(dtTimes1, timeid)

data.table::setnames(dtTimes1, old = ".period", new = perName)

} else {
stop("No period or count parameter provided")
}
}
}

data.table::setnames(dtTimes1, old = ".period", new = perName)
dtTimes1[]

}
Expand Down
12 changes: 6 additions & 6 deletions man/addPeriods.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

66 changes: 66 additions & 0 deletions tests/testthat/test-group_data.R
Original file line number Diff line number Diff line change
@@ -1,3 +1,69 @@
# addPariods
test_that("addPeriods works", {
skip_on_cran()

tdef <- defData(varname = "T", dist = "binary", formula = 0.5)
tdef <- defData(tdef, varname = "Y0", dist = "normal", formula = 10, variance = 1)
tdef <- defData(tdef, varname = "Y1", dist = "normal", formula = "Y0 + 5 + 5 * T", variance = 1)
tdef <- defData(tdef, varname = "Y2", dist = "normal", formula = "Y0 + 10 + 5 * T", variance = 1)

n <- ceiling(runif(1, 10, 20))
dtTrial <- genData(n, tdef)

p <- ceiling(runif(1, 3, 8))
dtTime <- addPeriods(
dtTrial,
nPeriods = p, idvars = "id"
)

expect_equal(nrow(dtTime), n*p)

expect_silent(
addPeriods(dtTrial,
nPeriods = 3, idvars = "id",
timevars = c("Y0", "Y1", "Y2"), timevarName = "Y",
periodVec = c(0, 3, 5)
)
)

expect_warning(
addPeriods(dtTrial,
nPeriods = 2, idvars = "id",
timevars = c("Y0", "Y1", "Y2"), timevarName = "Y"
)
)

testthat::expect_silent(
addPeriods(dtTrial,
nPeriods = 3, idvars = "id",
timevars = c("Y0", "Y1", "Y2"),
timevarName = "Y"
)
)

def <- defData(varname = "xbase", dist = "normal", formula = 20, variance = 3)
def <- defData(def, varname = "nCount", dist = "noZeroPoisson", formula = 6)
def <- defData(def, varname = "mInterval", dist = "gamma", formula = 30, variance = .01)
def <- defData(def, varname = "vInterval", dist = "nonrandom", formula = .07)

dt <- genData(50, def)
expect_silent(addPeriods(dt))


def <- defData(varname = "xbase", dist = "normal", formula = 20, variance = 3)
def <- defData(def, varname = "nCount", dist = "noZeroPoisson", formula = 6)
def <- defData(def, varname = "mInterval", dist = "gamma", formula = 30, variance = .01)

dt <- genData(50, def)
expect_silent(addPeriods(dt))

def <- defData(varname = "xbase", dist = "normal", formula = 20, variance = 3)

dt <- genData(50, def)
expect_error(addPeriods(dt))

})

# .addStrataCode ----
test_that("strata codes are added as expected.", {
skip_on_cran()
Expand Down

0 comments on commit e21cb03

Please sign in to comment.