utilityFunctions.R 9.07 KB
Newer Older
1 2 3 4
#' @include mortalityTable.R
NULL


5
fitExtrapolationLaw = function(data, ages, data.ages = ages, Dx = NULL, Ex = NULL, qx = NULL, method = "LF2", law = "HP", fit = 75:99, extrapolate = 80:120, fadeIn = 80:90, fadeOut = NULL, verbose = FALSE) {
6 7 8 9 10 11 12 13 14 15 16
    # Add the extrapolate ages to the needed ages
    neededAges = union(ages, extrapolate)
    # constrain the fit and fade-in range to given ages
    fit = intersect(ages, fit)
    if (!is.null(fadeIn))
        fadeIn = intersect(ages, fadeIn)
    if (!is.null(fadeOut))
        fadeOut = intersect(ages, fadeOut)

    # Hohe Alter: Fitte Heligman-Pollard im Bereich 75-99
    fitLaw = MortalityLaw(
17
        x = data.ages, Dx = Dx, Ex = Ex, qx = qx,
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
        law = law, opt.method = method,
        fit.this.x = fit)
    # summary(fitAP.m.75.99)
    # plot(fitAP.m.75.99)
    qPredict = predict(fitLaw, extrapolate)

    weights = rep(0, length(neededAges))
    names(weights) = neededAges

    if (!is.null(fadeIn)) {
        weights[neededAges < min(fadeIn)] = 0
        fadeInLen = length(fadeIn);
        weights[match(fadeIn, neededAges)] = (0:(fadeInLen - 1)) / (fadeInLen - 1)
        weights[neededAges > max(fadeIn)] = 1
    } else if (!is.null(fadeOut)) {
        weights[neededAges < min(fadeOut)] = 1
        fadeOutLen = length(fadeOut);
        weights[match(fadeOut, neededAges)] = ((fadeOutLen - 1):0) / (fadeOutLen - 1)
        weights[neededAges > max(fadeOut)] = 0
    }

    probs = fillAges(qPredict, givenAges = extrapolate, neededAges = neededAges, fill = 0) * weights +
        fillAges(data, givenAges = ages, neededAges = neededAges, fill = 0) * (1 - weights)

    if (verbose) {
        list(probs = probs, law = fitLaw, weights = weights)
    } else {
        probs
    }
}




# Fit an exponential function exp(-A*(x-x0)) to the last value (f(100) and f'(100) need to coincide):
fitExpExtrapolation = function(data, idx, up = TRUE, verbose = FALSE) {
    # browser()
    # Anchor point of the extrapolation
    f0 = data[[idx]]
    if (up) {
        A = -(data[[idx]] - data[[idx - 1]]) / f0
    } else {
        A = -(data[[idx + 1]] - data[[idx]]) / f0
    }
    x0 = idx + (log(f0) / A)
    fun.extra = function(x) exp(-A*(x - x0))
    if (up) {
        newdata = c(data[1:idx], sapply((idx + 1):length(data), fun.extra))
    } else {
        newdata = c(sapply(1:(idx - 1), fun.extra), data[idx:length(data)])
    }
    if (verbose) {
        list(data = newdata, A = A, x0 = x0, idx = idx)
    } else {
        newdata
    }
}


#' @export
mT.setName = function(table, name = table@name) {
79 80 81
    if (is.list(table)) {
        return(lapply(table, mT.setName, name = name))
    }
82
    if (!is(table, "mortalityTable"))
83
        stop("First argument must be a mortalityTable or a list of mortalityTable objects.")
84 85 86 87 88 89 90 91 92

    table@name = name
    table
}



#' @export
mT.fillAges = function(table, neededAges, fill = 0) {
93 94 95
    if (is.list(table)) {
        return(lapply(table, mT.fillAges, neededAges = neededAges, fill = fill))
    }
96
    if (!is(table, "mortalityTable"))
97
        stop("First argument must be a mortalityTable or a list of mortalityTable objects.")
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118

    existingAges = ages(table)
    if (.hasSlot(table, "ages"))
        table@ages = neededAges
    if (.hasSlot(table, "deathProbs"))
        table@deathProbs = fillAges(table@deathProbs, givenAges = existingAges, neededAges = neededAges, fill = fill)
    if (.hasSlot(table, "exposures") && !is.null(table@exposures) && length(table@exposures) > 1)
        table@exposures = fillAges(table@exposures, givenAges = existingAges, neededAges = neededAges, fill = 0)
    if (.hasSlot(table, "trend") && !is.null(table@trend) && length(table@trend) > 1)
        table@trend = fillAges(table@trend, givenAges = existingAges, neededAges = neededAges, fill = 0)
    if (.hasSlot(table, "trend2") && !is.null(table@trend2) && length(table@trend2) > 1)
        table@trend2 = fillAges(table@trend2, givenAges = existingAges, neededAges = neededAges, fill = 0)
    if (.hasSlot(table, "loading") && !is.null(table@loading) && length(table@loading) > 1)
        table@loading = fillAges(table@loading, givenAges = existingAges, neededAges = neededAges, fill = 0)
    if (!is.null(table@data$deaths))
        table@data$deaths = fillAges(table@data$deaths, givenAges = existingAges, neededAges = neededAges, fill = 0)
    table
}

#' @export
mT.scaleProbs = function(table, factor = 1.0, name.postfix = "scaled", name = paste(table@name, name.postfix)) {
119 120 121 122 123 124
    if (is.list(table)) {
        return(lapply(table, mT.scaleProbs, factor = factor, name.postfix = name.postfix, name = name))
    }
    if (!is(table, "mortalityTable"))
        stop("First argument must be a mortalityTable or a list of mortalityTable objects.")

125 126 127 128 129 130 131 132 133
    table@deathProbs = factor * table@deathProbs
    if (!is.null(name)) {
        table@name = name
    }
    table
}


#' @export
134
mT.setTrend = function(table, trend, trendages = ages(table), baseYear = table@baseYear, dampingFunction = identity) {
135 136 137
    if (is.list(table)) {
        return(lapply(table, mT.setTrend, trend = trend, trendages = trendages, baseYear = baseYear, dampingFunction = dampingFunction))
    }
138
    if (!is(table, "mortalityTable"))
139
        stop("First argument must be a mortalityTable or a list of mortalityTable objects.")
140 141 142 143

    t = mortalityTable.trendProjection(
        table,
        baseYear = baseYear,
144 145
        trend = trend[match(table@ages, trendages)],
        dampingFunction = dampingFunction
146 147 148 149 150 151 152 153 154 155 156
    )
    t
}
#' @describeIn mT.setTrend Add a trend to the mortality table (returns a mortalityTable.trendProjection obect)
#' @export
mT.addTrend = mT.setTrend



#' @export
mT.extrapolateTrendExp = function(table, idx, up = TRUE) {
157 158 159
    if (is.list(table)) {
        return(lapply(table, mT.extrapolateTrendExp, idx = idx, up = up))
    }
160
    if (!is(table, "mortalityTable"))
161
        stop("First argument must be a mortalityTable or a list of mortalityTable objects.")
162 163 164 165 166 167 168 169 170 171 172

    if (.hasSlot(table, "trend") && !is.null(table@trend))
        table@trend = fitExpExtrapolation(table@trend, idx = idx,up = up)
    if (.hasSlot(table, "tren2") && !is.null(table@trend2))
        table@trend2 = fitExpExtrapolation(table@trend2, idx = idx,up = up)
    table
}


#' @export
mT.translate = function(table, baseYear, name = table@name) {
173 174 175
    if (is.list(table)) {
        return(lapply(table, mT.translate, baseYear = baseYear, name = name))
    }
176
    if (!is(table, "mortalityTable"))
177
        stop("First argument must be a mortalityTable or a list of mortalityTable objects.")
178 179 180 181 182 183 184 185 186 187

    table@deathProbs = periodDeathProbabilities(table, Period = baseYear)
    table@baseYear = baseYear
    table@name = name
    table
}


#' @export
mT.extrapolateProbsExp = function(table, age, up = TRUE) {
188 189 190
    if (is.list(table)) {
        return(lapply(table, mT.extrapolateProbsExp, age = age, up = up))
    }
191
    if (!is(table, "mortalityTable"))
192
        stop("First argument must be a mortalityTable or a list of mortalityTable objects.")
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209

    if (.hasSlot(table, "deathProbs")) {
        idx = match(age, ages(table))
        fit = fitExpExtrapolation(table@deathProbs, idx = idx, up = up, verbose = TRUE)
        table@deathProbs = fit$data
        table@data$extrapolationData = c(
            table@data$extrapolationData,
            list(list(law = "Exp", idx = idx, up = up, fit = fit)))
    }
    table
}


#' @export
mT.fitExtrapolationLaw = function(table, method = "LF2", law = "HP",
                                  fit = 75:99, extrapolate = 80:120,
                                  fadeIn = 80:90, fadeOut = NULL) {
210 211 212
    if (!is(table, "mortalityTable"))
        stop("First argument must be a mortalityTable.")

213
    ages = ages(table)
214 215 216
    # if (!is.null(table@exposures) && !is.na(table@exposures)) {
        # Ex = table@exposures
        # qx = table@deathProbs
217 218 219 220 221
        # if (!is.null(table@data$deaths)) {
        #     Dx = table@data$deaths
        # } else {
        #     Dx = table@deathProbs * Ex
        # }
222 223
    # } else {
        # Ex = rep(1, length(ages))
224
        # Dx = table@deathProbs
225 226
        # qx = table@deathProbs
    # }
227 228 229
    table  = mT.fillAges(table, neededAges = union(ages, extrapolate), fill = 0)
    fitted = fitExtrapolationLaw(
        data = table@deathProbs, ages = ages(table),
230
        qx = table@deathProbs, data.ages = ages,
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
        method = method, law = law,
        fit = fit, extrapolate = extrapolate,
        fadeIn = fadeIn, fadeOut = fadeOut,
        verbose = TRUE
    )
    # Store all fit parameters in the data slot of the mortality table
    table@data$extrapolationData = c(
        table@data$extrapolationData,
        list(list(law = law, method = method, fit = fit,
                  extrapolate = extrapolate, fadeIn = fadeIn, fadeOut = fadeOut,
                  fit = fitted)))
    table@deathProbs = fitted$probs

    table
}

247 248
#' @export
mT.setDimInfo = function(table, ..., append = TRUE) {
249 250 251
    if (is.list(table)) {
        return(lapply(table, mT.setDimInfo, ..., append = append))
    }
252
    if (!is(table, "mortalityTable"))
253
        stop("First argument must be a mortalityTable or a list of mortalityTable objects.")
254 255 256 257 258 259 260 261 262

    if (append) {
        table@data$dim[names(list(...))] = list(...)
    } else {
        table@data$dim = list(...)
    }
    table
}