Fuzzy survival analysis for data in which event times and/or failure indicators are vague, for instance when a failure is only known to have occurred during the second quarter of a year, or when it is uncertain whether a subject lost to follow-up had in fact failed. Vague information is represented by fuzzy numbers. The package provides a fuzzy product-limit estimator obtained from nested alpha-cuts of the fuzzy survival function, a fuzzy Cox proportional hazards model with fuzzy coefficient and hazard ratio estimates, and a fuzzy log-rank test. Type-reduction utilities for summarizing fuzzy estimates by single numbers, a simulation engine for validation studies, plotting, print and summary methods, and alpha-cut based confidence bands are provided. The bounds are computed at the alpha-cuts of the fuzzy event times, so the alpha-cut intervals returned for the survival function, the regression coefficients and the test statistic are nested by construction.
Fuzzy survival analysis for data with vague event times and vague failure indicators.
Survival records are often imprecise: a failure is known to have happened
"during the second quarter", between two follow-up visits, or not at all - a
subject lost to follow-up may or may not have failed. fuzzySurvival models
that imprecision directly instead of discarding it or forcing an arbitrary
choice, and reports the whole consequence on the estimation rather than a
single number.
The package implements the alpha-cut extension of the Kaplan-Meier estimator, of the Cox proportional hazards model and of the log-rank test, together with the type-reduction (defuzzification) rules needed to turn a fuzzy result into a single interpretable quantity.
# from a local checkout
install.packages(".", repos = NULL, type = "source")
Survival analysis with fuzzy numbers is not covered by any CRAN package.
FuzzyNumbers and friends provide the fuzzy-set machinery, but nothing connects
it to censoring and to the partial likelihood; survival covers crisp data
only. The two ingredients are trivially combined once the algebra is right, but
the result has to satisfy properties that ordinary code breaks:
survival.Both properties are covered by the test suite.
Vague event times. The membership function of the event time says how plausible each value is. A failure observed between two examinations gives a flat fuzzy number on the interval between them (the value is entirely plausible anywhere in it); a rounded recollection gives a trapezoid.
library(fuzzySurvival)
# "the failure occurred in the second quarter" (months 4 to 6)
fuzzy_number_interval(4, 6)
#> <fuzzy_number> with 1 element
#> [1] "I[4, 6]"
# certainly between 3 and 9, plausibly concentrated in 5-7
fuzzy_number_trapezoid(3, 5, 7, 9)
Vague failure indicators. A status strictly between 0 and 1 is read as the degree of belief that the subject failed. Such a subject contributes a fractional number of events, and stays in the risk set until they are censored:
fuzzy_surv(c(2, 5, 7, 9), c(1, 0.5, 1, 1))
At level alpha the data compatible with the information are the box of times
between the alpha-cuts. Replacing each time by the lower or the upper end of its
cut makes the failures happen as early or as late as possible, so the two
Kaplan-Meier curves bound the survival function:
data(fuzzy_dfs)
fit <- fkm(fuzzy_surv(ft, fs) ~ 1, data = fuzzy_dfs)
fit
#> Fuzzy Kaplan-Meier estimate
#> n = 240, events = 81, uncertain = 40, alpha levels = 21
#> mean width of the alpha-cuts at level 0: 0.675
summary(fit, times = c(6, 12, 24))[, c("time", "n.risk", "lower", "surv", "upper")]
#> time n.risk lower surv upper
#> 1 6 212 0.00000 0.9781 0.9781
#> 2 12 187 0.9360 0.9410 0.9460
#> 3 24 129 0.7668 0.7784 0.7900
lower and upper are the bounds at the requested level, surv the
defuzzified curve. On precise data the two bounds coincide and the estimator
reproduces survival::survfit() exactly.
The same construction is applied to the partial likelihood: the alpha-cut of a coefficient spans every value obtained at a level at or below it, which is what makes the intervals nested. Hazard ratios keep their membership structure because the exponential is monotone.
fcox(fuzzy_surv(ft, fs) ~ age + arm, data = fuzzy_dfs)
#> Fuzzy Cox proportional hazards model
#>
#> coef p fuzzy.lower fuzzy.upper
#> age -0.0465 7.914e-05 -0.0696 -0.0234
#> arm 0.5211 0.005565 0.1527 0.8895
flogrank(fuzzy_surv(ft, fs) ~ arm, data = fuzzy_dfs)
#> Fuzzy log-rank test
#> n = 240, groups: Control vs Treated
#> observed / expected events in group 1: 49 / 65.66
#> crisp chi-square (level 1): 9.3273
#> crisp p-value: 0.002258
On crisp data this reproduces survival::survdiff().
A fuzzy result carries a whole family of alpha-cuts; a single number is obtained
by a type-reduction rule. Nine classical rules are available - midrange,
centroid, gmirl, sgmrl, ms, msm, yager, min, max:
defuzz(fuzzy_number_trapezoid(3, 5, 7, 9), "centroid")
#> [1] 6
# the fuzzy survival probability itself, reduced at three levels
defuzz(fkm_fuzzy_surv(fit, times = c(6, 12, 24)), "midrange", level = 0.5)
Every rule of a symmetric fuzzy number returns its centre, which makes the rules easy to check:
defuzz(fuzzy_number_triangle(2, 5, 8), c("centroid", "gmirl", "sgmrl"))
#> centroid gmirl sgmrl
#> [1,] 5 5 5
sim_fuzzy_surv() generates exact event times and then coarsens them the way a
record does, so that a study can be validated against a known truth:
set.seed(1)
d <- sim_fuzzy_surv(n = 200, beta = c(age = 0.4, arm = -0.5))
head(d[, c("arm", "fs")])
fit <- fkm(fuzzy_surv(ft, fs) ~ arm, data = d)
plot(fit, type = "diff")
vignette("fuzzy-survival", package = "fuzzySurvival") walks through the
construction, the estimation, and the caveats. ?fkm, ?fcox, ?flogrank and
?fuzzy_number give the reference.
alpha. Use a trapezoid when the
plausibility of the values should be graded.MIT