Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

estimateParams() #84

Merged
merged 60 commits into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
0c93a5b
add draft for design check
holgstr Nov 7, 2023
d75c37c
Merge 0c93a5b61a2f5841757b6350106a4fb680583ea5 into fda7e6921ef60116d…
holgstr Nov 7, 2023
fd3404d
[skip actions] Restyle files
github-actions[bot] Nov 7, 2023
7bd34ae
Add progress bar to getClinicalTrials (#85)
holgstr Nov 7, 2023
66bd151
[skip actions] Bump version to 0.0.5.9017
holgstr Nov 7, 2023
36c4002
add S3 method
holgstr Nov 8, 2023
15a2886
Merge 36c4002e9f24a571b183e1b41a3a5baa627b5aa2 into 66bd151abb1c906f6…
holgstr Nov 8, 2023
30a39c9
[skip actions] Restyle files
github-actions[bot] Nov 8, 2023
41465b7
add feedback
holgstr Nov 9, 2023
5153b89
getTarget function
holgstr Nov 9, 2023
745c0ea
Merge 5153b89db65b3c4b4791a4c251dbbebd7b3d1bc9 into 66bd151abb1c906f6…
holgstr Nov 9, 2023
0433032
[skip actions] Restyle files
github-actions[bot] Nov 9, 2023
fa57e3b
add getResults and change optim method
holgstr Nov 10, 2023
e247b00
Merge fa57e3b417431dc44fe6d2a809a663560120ba0f into 66bd151abb1c906f6…
holgstr Nov 10, 2023
280437f
[skip actions] Restyle files
github-actions[bot] Nov 10, 2023
0e083b8
getInitial as S3 method
holgstr Nov 10, 2023
7787a3b
docu haz
holgstr Nov 10, 2023
d6fe757
docu survTrans
holgstr Nov 10, 2023
b943d42
getInitial docu
holgstr Nov 10, 2023
78c67da
docu getResults
holgstr Nov 10, 2023
c036fbc
add info to docu getInitial/getResults
holgstr Nov 10, 2023
0ec2e4a
docu negLogLik
holgstr Nov 10, 2023
812e7f5
add docu getTarget
holgstr Nov 10, 2023
347a80d
docu estimateParams
holgstr Nov 10, 2023
1db81c4
pkgdown
holgstr Nov 10, 2023
835843e
lint
holgstr Nov 10, 2023
da13286
Merge 835843e9429ee312da8f917249c1dd3db98aece5 into 66bd151abb1c906f6…
holgstr Nov 10, 2023
5f02f7c
[skip actions] Restyle files
github-actions[bot] Nov 10, 2023
e5ce2b8
pkgdown
holgstr Nov 10, 2023
eb9fb2a
docu fix
holgstr Nov 10, 2023
3fb18ba
spacing
holgstr Nov 10, 2023
bc4a5b3
Merge 3fb18ba6cbe48c78267330e3d92e640e47cbc847 into 66bd151abb1c906f6…
holgstr Nov 10, 2023
289ddea
[skip actions] Restyle files
github-actions[bot] Nov 10, 2023
d35fb5f
rename getInitial
holgstr Nov 10, 2023
e934e22
change examples
holgstr Nov 11, 2023
8600ff5
lint
holgstr Nov 11, 2023
1346609
Merge 8600ff5df489bac75ce6da167e872368e0a84cf2 into 66bd151abb1c906f6…
holgstr Nov 11, 2023
3cb6a90
[skip actions] Restyle files
github-actions[bot] Nov 11, 2023
3517aa7
add tests and news
holgstr Nov 12, 2023
b0c1b08
Update NEWS.md
holgstr Nov 13, 2023
3516f47
Update R/estimateParams.R
holgstr Nov 13, 2023
f96560a
Update R/estimateParams.R
holgstr Nov 13, 2023
e778d96
Update R/estimateParams.R
holgstr Nov 13, 2023
527bfbf
Update R/estimateParams.R
holgstr Nov 13, 2023
041b868
Update R/estimateParams.R
holgstr Nov 13, 2023
83a869f
Update R/estimateParams.R
holgstr Nov 13, 2023
5e986f6
Update R/estimateParams.R
holgstr Nov 13, 2023
3d98e6a
Update R/estimateParams.R
holgstr Nov 13, 2023
e26987e
Update R/estimateParams.R
holgstr Nov 13, 2023
a69a6b0
Update R/estimateParams.R
holgstr Nov 13, 2023
9dd7cce
Update R/estimateParams.R
holgstr Nov 13, 2023
110effe
Update R/estimateParams.R
holgstr Nov 13, 2023
3e22bcb
Update R/estimateParams.R
holgstr Nov 13, 2023
2e22fd0
Update R/estimateParams.R
holgstr Nov 13, 2023
881c8b0
Update R/estimateParams.R
holgstr Nov 13, 2023
cd5d2a1
Update R/estimateParams.R
holgstr Nov 13, 2023
06d2488
Update R/estimateParams.R
holgstr Nov 13, 2023
0395420
include feedback
holgstr Nov 13, 2023
a853d43
Merge 039542049d4341ba0476bb1cf41ab2d925ddf13b into 66bd151abb1c906f6…
holgstr Nov 13, 2023
a6c4ea8
[skip actions] Restyle files
github-actions[bot] Nov 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Generated by roxygen2: do not edit by hand

S3method(getInit,ExponentialTransition)
S3method(getInit,WeibullTransition)
S3method(getResults,ExponentialTransition)
S3method(getResults,WeibullTransition)
S3method(getTarget,ExponentialTransition)
S3method(getTarget,WeibullTransition)
S3method(haz,ExponentialTransition)
S3method(haz,WeibullTransition)
S3method(survTrans,ExponentialTransition)
S3method(survTrans,WeibullTransition)
export(ExpHazOS)
export(ExpQuantOS)
export(ExpSurvOS)
Expand All @@ -18,26 +28,33 @@ export(avgHRExpOS)
export(avgHRIntegExpOS)
export(censoringByNumberEvents)
export(empSignificant)
export(estimateParams)
export(exponential_transition)
export(getCensoredData)
export(getClinicalTrials)
export(getDatasetWideFormat)
export(getEventsAll)
export(getInit)
export(getNumberEvents)
export(getOneClinicalTrial)
export(getOneToTwoRows)
export(getPCWDistr)
export(getPCWHazard)
export(getResults)
export(getSimulatedData)
export(getSumPCW)
export(getTarget)
export(getTimePoint)
export(getWaitTimeSum)
export(haz)
export(integrateVector)
export(logRankTest)
export(negLogLik)
export(passedLogRank)
export(piecewise_exponential)
export(prepareData)
export(pwA)
export(survTrans)
export(trackEventsPerTrial)
export(weibull_transition)
import(checkmate)
Expand Down
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
### New Features

- `prepareData` allows formatting of trial data for log-likelihood computation.
- `estimateParams` estimates parameters of exponential and Weibull transition hazards for a given data set.

### Bug Fixes

Expand Down
304 changes: 304 additions & 0 deletions R/estimateParams.R
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,307 @@ prepareData <- function(data) {

as.data.frame(dataNew[, -which(names(dataNew) == "time")], row.names = seq_len(nrow(dataNew)))
}

#' Compute the Negative Log-Likelihood for a Given Data Set and Transition Model
#'
#' @param transition (`ExponentialTransition` or `WeibullTransition`)\cr
#' see [exponential_transition()] or [weibull_transition()] for details.
#' @param data (`data.frame`)\cr in the format created by [prepareData()].
#'
#' @return The value of the negative log-likelihood.
#' @export
#'
#' @details
#' Calculates the negative log-likelihood for a given data set and transition model. It uses the hazard
#' and survival functions specific to the transition model.
#'
#' @examples
#' transition <- exponential_transition(h01 = 1.2, h02 = 1.5, h12 = 1.6)
#' simData <- getOneClinicalTrial(
#' nPat = c(30), transitionByArm = list(transition),
#' dropout = list(rate = 0.8, time = 12),
#' accrual = list(param = "time", value = 1)
#' )
#' negLogLik(transition, prepareData(simData))
negLogLik <- function(transition, data) {
with(data, -sum(log(haz(transition, exit, trans)^status
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please reindent/add line breaks to fix linter error

* survTrans(transition, exit, trans) / survTrans(transition, entry, trans))))
}

#' Hazard Function for Different Transition Models
#'
#' @param transition (`ExponentialTransition` or `WeibullTransition`)\cr
#' see [exponential_transition()] or [weibull_transition()] for details.
#' @param t (`numeric`)\cr time at which hazard is to be computed.
#' @param trans (`integer`)\cr index specifying the transition type.
#'
#' @return The hazard rate for the specified transition and time.
#' @export
#'
#' @examples
#' transition <- exponential_transition(h01 = 1.2, h02 = 1.5, h12 = 1.6)
#' haz(transition, 0.4, 2)
haz <- function(transition, t, trans) {
assert_class(transition, "TransitionParameters")
assert_numeric(t, lower = 0)
assert_subset(trans, c(1, 2, 3))
UseMethod("haz")
}

#' @describeIn haz for an exponential transition model.
#' @export
#'
#' @examples
#' transition <- exponential_transition(h01 = 1.2, h02 = 1.5, h12 = 1.6)
#' haz(transition, 0.4, 2)
haz.ExponentialTransition <- function(transition, t, trans) {
# params (in this order): h01, h02, h12.
params <- unlist(transition$hazards, use.names = FALSE)
params[trans]
}

#' @describeIn haz for the Weibull transition model.
#' @export
#'
#' @examples
#' transition <- weibull_transition(h01 = 1.2, h02 = 1.5, h12 = 1.6, p01 = 2, p02 = 2.5, p12 = 3)
#' haz(transition, 0.4, 2)
haz.WeibullTransition <- function(transition, t, trans) {
# params (in this order): h01, h02, h12, p01, p02, p12.
params <- c(unlist(transition$hazards, use.names = FALSE), unlist(transition$weibull_rates, use.names = FALSE))
params[trans] * params[trans + 3] * t^(params[trans + 3] - 1)
}

#' Survival Function for Different Transition Models
#'
#' @param transition (`ExponentialTransition` or `WeibullTransition`)\cr
#' see [exponential_transition()] or [weibull_transition()] for details.
#' @param t (`numeric`)\cr time at which survival probability is to be computed.
#' @param trans (`integer`)\cr index specifying the transition type.
#'
#' @return The survival probability for the specified transition and time.
#' @export
#'
#' @examples
#' transition <- exponential_transition(h01 = 1.2, h02 = 1.5, h12 = 1.6)
#' survTrans(transition, 0.4, 2)
survTrans <- function(transition, t, trans) {
assert_class(transition, "TransitionParameters")
assert_numeric(t, lower = 0)
assert_subset(trans, c(1, 2, 3))
UseMethod("survTrans")
}

#' @describeIn survTrans for the Exponential Transition Model
#' @export
#'
#' @examples
#' transition <- exponential_transition(h01 = 1.2, h02 = 1.5, h12 = 1.6)
#' survTrans(transition, 0.4, 2)
survTrans.ExponentialTransition <- function(transition, t, trans) {
# params (in this order): h01, h02, h12.
params <- unlist(transition$hazards, use.names = FALSE)
exp(-params[trans] * t)
}

#' @describeIn survTrans for the Weibull Transition Model
#' @export
#'
#' @examples
#' transition <- weibull_transition(h01 = 1.2, h02 = 1.5, h12 = 1.6, p01 = 2, p02 = 2.5, p12 = 3)
#' survTrans(transition, 0.4, 2)
survTrans.WeibullTransition <- function(transition, t, trans) {
# params (in this order): h01, h02, h12, p01, p02, p12.
params <- c(unlist(transition$hazards, use.names = FALSE), unlist(transition$weibull_rates, use.names = FALSE))
exp(-params[trans] * t^params[trans + 3])
}

#' Retrieve Initial Parameter Vectors for Likelihood Maximization
#'
#' @param transition (`ExponentialTransition` or `WeibullTransition`)\cr containing the initial parameters.
#' See [exponential_transition()] or [weibull_transition()] for details.
#'
#' @return The numeric vector of initial parameters for likelihood maximization.
#' @export
#'
#' @examples
#' transition <- exponential_transition(h01 = 1.2, h02 = 1.5, h12 = 1.6)
#' getInit(transition)
getInit <- function(transition) {
assert_class(transition, "TransitionParameters")
UseMethod("getInit")
}

#' @describeIn getInit for the Exponential Transition Model
#' @export
#'
#' @examples
#' transition <- exponential_transition(h01 = 1.2, h02 = 1.5, h12 = 1.6)
#' getInit(transition)
getInit.ExponentialTransition <- function(transition) {
unlist(transition$hazards, use.names = FALSE)
}

#' @describeIn getInit for the Weibull Transition Model
#' @export
#'
#' @examples
#' transition <- weibull_transition(h01 = 1.2, h02 = 1.5, h12 = 1.6, p01 = 2, p02 = 2.5, p12 = 3)
#' getInit(transition)
getInit.WeibullTransition <- function(transition) {
c(unlist(transition$hazards, use.names = FALSE), unlist(transition$weibull_rates, use.names = FALSE))
}

#' Generate the Target Function for Optimization
#'
#' @param transition (`TransitionParameters`)\cr
#' specifying the distribution family. See [exponential_transition()] or [weibull_transition()] for details.
#'
#' @return Function that calculates the negative log-likelihood for the given parameters.
#' @export
#'
#' @details
#' This function creates a target function for optimization, computing the negative log-likelihood for given
#' parameters, data, and transition model type.
#'
#' @examples
#' transition <- exponential_transition(2, 1.3, 0.8)
#' simData <- getOneClinicalTrial(
#' nPat = c(30), transitionByArm = list(transition),
#' dropout = list(rate = 0.8, time = 12),
#' accrual = list(param = "time", value = 1)
#' )
#' params <- c(1.2, 1.5, 1.6) # For ExponentialTransition
#' data <- prepareData(simData)
#' transition <- exponential_transition()
#' fun <- getTarget(transition)
#' fun(params, data)
getTarget <- function(transition) {
assert_class(transition, "TransitionParameters")
UseMethod("getTarget", transition)
}

#' @describeIn getTarget for the Exponential Transition Model
#' @export
#'
#' @examples
#' transition <- exponential_transition(2, 1.3, 0.8)
#' simData <- getOneClinicalTrial(
#' nPat = c(30), transitionByArm = list(transition),
#' dropout = list(rate = 0.8, time = 12),
#' accrual = list(param = "time", value = 1)
#' )
#' params <- c(1.2, 1.5, 1.6)
#' data <- prepareData(simData)
#' transition <- exponential_transition()
#' target <- getTarget(transition)
#' target(params, data)
getTarget.ExponentialTransition <- function(transition) {
function(params, data) {
negLogLik(transition = exponential_transition(h01 = params[1], h02 = params[2], h12 = params[3]), data = data)
}
}

#' @describeIn getTarget for the Weibull Transition Model
#' @export
#'
#' @examples
#' transition <- weibull_transition(h01 = 1.2, h02 = 1.5, h12 = 1.6, p01 = 2, p02 = 2.5, p12 = 3)
#' simData <- getOneClinicalTrial(
#' nPat = c(30), transitionByArm = list(transition),
#' dropout = list(rate = 0.8, time = 12),
#' accrual = list(param = "time", value = 1)
#' )
#' params <- c(1.2, 1.5, 1.6, 0.8, 1.3, 1.1)
#' data <- prepareData(simData)
#' transition <- weibull_transition()
#' target <- getTarget(transition)
#' target(params, data)
getTarget.WeibullTransition <- function(transition) {
function(params, data) {
negLogLik(transition = weibull_transition(
h01 = params[1], h02 = params[2], h12 = params[3],
p01 = params[4], p02 = params[5], p12 = params[6]
), data = data)
}
}

#' Format Results of Parameter Estimation for Different Transition Models
#'
#' @param transition (`TransitionParameters`)\cr
#' see [exponential_transition()] or [weibull_transition()] for details.
#' @param res (`numeric` vector)\cr vector of parameter estimates from the likelihood maximization procedure.
#'
#' @return Returns a `TransitionParameters` object with parameter estimates.
#' @export
#'
#' @examples
#' results <- c(1.2, 1.5, 1.6)
#' getResults(exponential_transition(), results)
getResults <- function(transition, res) {
UseMethod("getResults")
}

#' @describeIn getResults for the Exponential Transition Model
#' @export
#'
#' @examples
#' results <- c(1.2, 1.5, 1.6)
#' getResults(exponential_transition(), results)
getResults.ExponentialTransition <- function(transition, res) {
exponential_transition(h01 = res[1], h02 = res[2], h12 = res[3])
}

#' @describeIn getResults for the Weibull Transition Model
#' @export
#'
#' @examples
#' results <- c(1.2, 1.5, 1.6, 2, 2.5, 1)
#' getResults(weibull_transition(), results)
getResults.WeibullTransition <- function(transition, res) {
weibull_transition(
h01 = res[1], h02 = res[2], h12 = res[3],
p01 = res[4], p02 = res[5], p12 = res[6]
)
}

#' Estimate Parameters of the Multistate Model Using Clinical Trial Data
#'
#' @param data (`data.frame`)\cr in the format produced by [getOneClinicalTrial()].
#' @param transition (`TransitionParameters` object)\cr specifying the assumed distribution of transition hazards.
#' Initial parameters for optimization can be specified here.
#' See [exponential_transition()] or [weibull_transition()] for details.
#'
#' @return Returns a `TransitionParameters` object with the estimated parameters.
#' @export
#'
#' @details
#' This function estimates parameters for transition models using clinical trial data.
#' The `transition` object can be initialized with starting values for parameter estimation.
#' It uses [stats::optim()] to optimize the parameters.
#'
#' @examples
#' transition <- exponential_transition(h01 = 2, h02 = 1.4, h12 = 1.6)
#' simData <- getOneClinicalTrial(
#' nPat = c(30), transitionByArm = list(transition),
#' dropout = list(rate = 0.3, time = 12),
#' accrual = list(param = "time", value = 1)
#' )
#' # Initialize transition with desired starting values for optimization:
#' transition <- exponential_transition(h01 = 1.2, h02 = 1.5, h12 = 1.6)
#' estimate <- estimateParams(simData, transition)
estimateParams <- function(data, transition) {
data <- prepareData(data)
par <- getInit(transition)
target <- getTarget(transition)

res <- stats::optim(
par = par,
fn = target,
method = "L-BFGS-B",
lower = 1e-3,
data = data
)$par

getResults(transition, res)
}
Loading