pierucci / heemod

:chart_with_upwards_trend:Markov Models for Health Economic Evaluations
https://pierucci.org/heemod/
Other
41 stars 25 forks source link

Potential Improvements to Partitioned Survival Models #243

Open jrdnmdhl opened 7 years ago

jrdnmdhl commented 7 years ago

Thought about this a bit, and I have a few ideas to share. # 1 I think is straightforward. # 2 is a bit more complicated but probably worthwhile. # 3 is way out there, but perhaps may solve problem down the line or inspire a more practical idea.

1. Handling cases where PFS > OS

If I am reading the part_surv.R correctly, heemod will throw an error when PFS > OS (since this leads to negative PPS). I think this is probably overly cautious. While PFS > OS can indicate a serious problem, it can also sometimes be trivial. It is often even unavoidable in a PSA. In general, I think it makes some sense to restrict that PFS <= OS and to warn the user to check their distributions when this happens rather than stopping. In particular, the PSA would ideally warn users about the number of times it happens so that they can understand the severity of the problem.

2. Support for n-state models

While most PSMs are 3-state models, they can in fact be generalized to any number of states, as long as patients progress through those states in an ordered sequence. A few examples of where this is useful:

I imagine the user syntax for this would look something like specifying the n-1 survival distributions in the dots using the argument names specified as the names of the states defined by those transitions with an additional argument for the name of the absorbing state:

define_part_surv <- function(..., absorbing_state="Dead", cycle_length = 1) {
    # Hard part goes here
}

3. Independent Partitions

Another way to expand the flexibility of partitioned survival models is to create non-mutually exclusive states. OS for a given comparator can be partitioned into pre-progression and post-progression, for the purposes of QALYs and disease-related costs, but it can also (independently) be partitioned into on-treatment and off-treatment for the purposes of treatment-related costs.

In heemod terms, I suppose this would look like supplying multiple sets of distribution arguments to define_part_surv. Before I learned of heemod, I was working on a data structure to define models with an arbitrary number of states and independent partitions, and I came up with this: https://gist.github.com/jrdnmdhl/7acb07a7bbf7c83e9a737b74c2de4c9c

Much less advanced than heemod, though not entirely dissimilar.

jrdnmdhl commented 7 years ago

For illustration, I have put together a basic implementation of suggestions 1 and 2 in a new branch here: https://github.com/jrdnmdhl/heemod/blob/amdahl-part-surv/R/part_surv.R

MattWiener commented 7 years ago

Hi, Jordan. Sorry for the slow response. On point #1. Progression free survival, as a form of survival, just can't be greater than overall survival, and I still think it makes sense for it to be an error if that happens. I'm not sure how it would be inevitable for it to occur in a psa - I think it can always be specified in a way that doesn't allow the problem to occur.

If we want to allow for the possibility of running analyses where this does happen, I'd be inclined to create an explicit over-ride, an argument like allow.pfs.gt.os, which would be FALSE by default. If allow.pfs.gt.os were FALSE, we would get the current behavior with an error thrown if pfs > os. If it's TRUE, the analysis would proceed, with a warning that tells you how many times it happens. That would make sure that only users who really think about it and understand what they are doing would use the option.

I will try to take a look at your code on #2 soon, but I certainly like the idea of expanding to more states. My only question would be to what extent we could leverage the mstate package for that.

jrdnmdhl commented 7 years ago

Hi Matt, thanks for your comments.

I would be interested to hear how you would recommend specifying PFS/OS to avoid this issue in the PSA.

As a side note, while it is true that PFS can't exceed OS with full information, Kaplan-Meier PFS can exceed Kaplan-Meier OS even under innocuous circumstances. Not only is this logically possible, I have seen it happen "in the wild". Example:

testsurv = data.frame(
    id=c(1,2,3,1,2,3),
    analysis=c("PFS","PFS","PFS","OS","OS","OS"),
    time=c(1,2,4,3,2,4),
    flag=c(1,0,0,1,0,0)
)
plot(survfit(Surv(time,flag)~analysis,data=testsurv))

As for the second item, I think mstate functionality would probably represent a third calculation engine distinct from markov and partitioned survival models. I'm not terribly familiar with it, but I imagine it wouldn't neatly fit into the same syntax as a standard 3-state partitioned survival model.

What I am suggesting here is more of a simple expansion of the existing partitioned survival model functionality, where 3-state models would be a special case where the syntax is almost exactly the same as it is now.