| Title: | Worked Derivations for Classical Epidemiological Measures |
|---|---|
| Description: | Computes classical epidemiological measures and returns the complete worked derivation alongside the result: every intermediate quantity, the formula, and the formula with the observed numbers substituted in. Intended for teaching, for checking hand calculations, and for generating worked solutions in course materials. Scope is deliberately limited to methods a student can compute by hand on paper. Methods follow Mantel and Haenszel (1959) <doi:10.1093/jnci/22.4.719>, Greenland and Robins (1985, Biometrics 41, 55-68), Robins, Breslow and Greenland (1986, Biometrics 42, 311-323), and Breslow and Day (1980, IARC Scientific Publications No. 32). |
| Authors: | Raj Subedi [aut, cre] |
| Maintainer: | Raj Subedi <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.2.0 |
| Built: | 2026-10-09 07:48:27 UTC |
| Source: | https://github.com/rajsubediresearch/epibyhand |
The proportion of disease that would be prevented by removing the exposure,
either among the exposed (among = "exposed") or in the whole population
(among = "population").
attributable_fraction( x, ..., among = c("exposed", "population"), conf_level = 0.95 )attributable_fraction( x, ..., among = c("exposed", "population"), conf_level = 0.95 )
x |
An |
... |
Further cell counts if |
among |
|
conf_level |
Confidence level for the interval. |
For the population fraction the derivation computes the same quantity three ways – directly from risks, by Levin's formula from exposure prevalence, and by Miettinen's formula from the proportion of cases exposed – and shows that they agree. They are not competing estimators; they are one quantity written three ways, which is easier to believe once seen numerically.
An epibyhand_derivation.
Levin, M. L. (1953). The occurrence of lung cancer in man. Acta Unio Internationalis Contra Cancrum, 9(3), 531-541.
Miettinen, O. S. (1974). Proportion of disease caused or prevented by a given exposure, trait or intervention. American Journal of Epidemiology, 99(5), 325-332.
attributable_fraction(epi2x2(36, 14, 30, 25)) attributable_fraction(epi2x2(36, 14, 30, 25), among = "population")attributable_fraction(epi2x2(36, 14, 30, 25)) attributable_fraction(epi2x2(36, 14, 30, 25), among = "population")
Compare a value you computed by hand against the final estimate, or against
a named intermediate step. When the value does not match, check_work()
searches every step of the derivation for one that does – so instead of
"wrong", the student is told where they stopped or slipped.
check_work(x, value, step = NULL, tol = 0.005)check_work(x, value, step = NULL, tol = 0.005)
x |
An |
value |
Numeric. The value you computed by hand. |
step |
Optional. Which step to compare against: a step number, or the
symbol of a step such as |
tol |
Relative tolerance for the comparison. The default is loose enough to accept a value rounded to two decimal places. |
Invisibly, TRUE if the value matched the requested target.
d <- odds_ratio(epi2x2(36, 14, 30, 25)) check_work(d, 2.14) check_work(d, 2.571)d <- odds_ratio(epi2x2(36, 14, 30, 25)) check_work(d, 2.14) check_work(d, 2.571)
Adds the strata cell by cell, discarding the stratifying variable. The result is the crude table – the one you would have had if you had never stratified. Comparing a crude estimate with its adjusted counterpart is how confounding is made visible.
collapse_strata(x)collapse_strata(x)
x |
An |
An epi2x2.
collapse_strata(epi_strata(c(10, 20, 5, 40), c(30, 15, 20, 25)))collapse_strata(epi_strata(c(10, 20, 5, 40), c(30, 15, 20, 25)))
Confidence intervals in this package are computed when the measure is
computed, because the derivation displays the arithmetic that produced
them. level therefore cannot change the result here; supplying one that
differs from the level the derivation was built at raises a warning. Set
the level with the conf_level argument of the measure instead.
## S3 method for class 'epibyhand_derivation' confint(object, parm, level, ...)## S3 method for class 'epibyhand_derivation' confint(object, parm, level, ...)
object |
An |
parm |
Unused, for S3 consistency. |
level |
Ignored, with a warning if it differs from the level the
derivation was built at. Use |
... |
Unused. |
Numeric vector of length 2.
d <- odds_ratio(epi2x2(36, 14, 30, 25), conf_level = 0.99) confint(d)d <- odds_ratio(epi2x2(36, 14, 30, 25), conf_level = 0.99) confint(d)
Create a derivation object
derivation( method, estimate, symbol = NULL, ci = NULL, conf_level = 0.95, data = NULL, steps = list(), notes = character() )derivation( method, estimate, symbol = NULL, ci = NULL, conf_level = 0.95, data = NULL, steps = list(), notes = character() )
method |
Character. Name of the measure, e.g. |
estimate |
Numeric. The final point estimate. |
symbol |
Character. Symbol for the estimate, e.g. |
ci |
Numeric length-2 vector, or |
conf_level |
Confidence level used for |
data |
Optional. The input data object, printed above the steps. |
steps |
List of |
notes |
Character vector of assumption notes shown after the result. |
An object of class epibyhand_derivation.
A step is the atomic unit of a worked solution: a human-readable label, the symbolic formula, the same formula with observed values substituted in, and the numeric result.
derivation_step( label, formula, substituted, result, symbol = NULL, note = NULL, table = NULL )derivation_step( label, formula, substituted, result, symbol = NULL, note = NULL, table = NULL )
label |
Short description of what this step computes. |
formula |
Character. The formula in symbols, e.g. |
substituted |
Character. The formula with numbers filled in. |
result |
Numeric. The value this step evaluates to. |
symbol |
Optional character. The symbol this step defines, e.g. |
note |
Optional character. A caveat or explanation attached to the step. |
table |
Optional data frame. Per-unit working shown as a grid beneath the formula. Used when a step aggregates over strata and a single substituted line would be unreadable. |
An object of class epibyhand_step.
Accepts a list of epi2x2() objects, a list of four-element count vectors,
or a 2 x 2 x K array. Stratum labels are taken from the names of the list,
the third dimnames of the array, or generated as "Stratum 1", and so on.
epi_strata( ..., labels = NULL, exposure = c("Exposed", "Unexposed"), outcome = c("Case", "Non-case") )epi_strata( ..., labels = NULL, exposure = c("Exposed", "Unexposed"), outcome = c("Case", "Non-case") )
... |
Strata: |
labels |
Optional character vector of stratum names. |
exposure |
Length-2 character vector labelling the rows. |
outcome |
Length-2 character vector labelling the columns. |
An object of class epi_strata.
epi_strata(c(10, 20, 5, 40), c(30, 15, 20, 25), labels = c("Men", "Women"))epi_strata(c(10, 20, 5, 40), c(30, 15, 20, 25), labels = c("Men", "Women"))
Accepts either four cell counts or a 2 x 2 matrix/table. Orientation is exposure in rows, outcome in columns, with the index level first in each – the layout used in standard epidemiology texts.
epi2x2( a, b = NULL, c = NULL, d = NULL, exposure = c("Exposed", "Unexposed"), outcome = c("Case", "Non-case") )epi2x2( a, b = NULL, c = NULL, d = NULL, exposure = c("Exposed", "Unexposed"), outcome = c("Case", "Non-case") )
a |
Exposed cases, or a 2 x 2 matrix or table. |
b |
Exposed non-cases. |
c |
Unexposed cases. |
d |
Unexposed non-cases. |
exposure |
Length-2 character vector labelling the rows. |
outcome |
Length-2 character vector labelling the columns. |
An object of class epi2x2.
epi2x2(36, 14, 30, 25) epi2x2(matrix(c(36, 14, 30, 25), nrow = 2, byrow = TRUE))epi2x2(36, 14, 30, 25) epi2x2(matrix(c(36, 14, 30, 25), nrow = 2, byrow = TRUE))
Extract the point estimate from a derivation
estimate(x)estimate(x)
x |
An |
Numeric scalar.
Tests whether one common odds ratio can be assumed across strata – the
assumption that makes mh_odds_ratio() meaningful. The statistic is a sum
of per-stratum contributions, and those contributions are shown, so a
single badly behaved stratum can be seen rather than inferred.
homogeneity(x, ..., tarone = TRUE)homogeneity(x, ..., tarone = TRUE)
x |
An |
... |
Further strata if |
tarone |
Apply Tarone's correction. Defaults to |
Tarone's correction is applied by default; without it the statistic is slightly too large.
An epibyhand_derivation.
Breslow, N. E. and Day, N. E. (1980). Statistical Methods in Cancer Research, Volume I: The Analysis of Case-Control Studies. IARC Scientific Publications No. 32, Lyon.
Tarone, R. E. (1985). On heterogeneity tests based on efficient scores. Biometrika, 72(1), 91-95.
homogeneity(epi_strata(c(10, 20, 5, 40), c(30, 15, 20, 25)))homogeneity(epi_strata(c(10, 20, 5, 40), c(30, 15, 20, 25)))
Pools stratum-specific odds ratios into a single adjusted estimate, showing the stratum weights explicitly and comparing the result against the crude estimate so that confounding is visible as arithmetic.
mh_odds_ratio(x, ..., conf_level = 0.95)mh_odds_ratio(x, ..., conf_level = 0.95)
x |
An |
... |
Further strata if |
conf_level |
Confidence level for the interval. |
The confidence interval uses the Robins-Breslow-Greenland variance, which is valid both for a few large strata and for many small ones.
An epibyhand_derivation.
Mantel, N. and Haenszel, W. (1959). Statistical aspects of the analysis of data from retrospective studies of disease. Journal of the National Cancer Institute, 22(4), 719-748. doi:10.1093/jnci/22.4.719
Robins, J., Breslow, N. and Greenland, S. (1986). Estimators of the Mantel-Haenszel variance consistent in both sparse data and large-strata limiting models. Biometrics, 42(2), 311-323.
s <- epi_strata(c(10, 20, 5, 40), c(30, 15, 20, 25), labels = c("Men", "Women")) mh_odds_ratio(s)s <- epi_strata(c(10, 20, 5, 40), c(30, 15, 20, 25), labels = c("Men", "Women")) mh_odds_ratio(s)
Mantel-Haenszel risk ratio with worked derivation
mh_risk_ratio(x, ..., conf_level = 0.95)mh_risk_ratio(x, ..., conf_level = 0.95)
x |
An |
... |
Further strata if |
conf_level |
Confidence level for the interval. |
An epibyhand_derivation.
Greenland, S. and Robins, J. M. (1985). Estimation of a common effect parameter from sparse follow-up data. Biometrics, 41, 55-68.
mh_risk_ratio(epi_strata(c(10, 20, 5, 40), c(30, 15, 20, 25)))mh_risk_ratio(epi_strata(c(10, 20, 5, 40), c(30, 15, 20, 25)))
Odds ratio with worked derivation
odds_ratio(x, ..., conf_level = 0.95)odds_ratio(x, ..., conf_level = 0.95)
x |
An |
... |
Further cell counts if |
conf_level |
Confidence level for the interval. |
An epibyhand_derivation.
Woolf, B. (1955). On estimating the relation between blood group and disease. Annals of Human Genetics, 19, 251-253.
odds_ratio(epi2x2(36, 14, 30, 25))odds_ratio(epi2x2(36, 14, 30, 25))
Computes the positive or negative predictive value, showing sensitivity, specificity and prevalence as separate steps so that the dependence on prevalence is visible rather than asserted.
predictive_value( x, ..., which = c("positive", "negative"), prevalence = NULL, conf_level = 0.95 )predictive_value( x, ..., which = c("positive", "negative"), prevalence = NULL, conf_level = 0.95 )
x |
An |
... |
Further cell counts if |
which |
|
prevalence |
Optional. Apply the test to a population with this prevalence rather than the one observed in the table. No confidence interval is produced in that case, because the result is not a proportion estimated from these data. |
conf_level |
Confidence level for the interval. |
The table is expected in screening orientation, which is the same shape as every other table in this package once you read "exposed" as "test positive" and "case" as "diseased":
| Diseased | Healthy | |
| Test + | a (TP) | b (FP) |
| Test - | c (FN) | d (TN) |
Supplying prevalence applies the test's sensitivity and specificity to a
population with that prevalence instead of the one in the table, via Bayes'
theorem. This is how you answer "what would this test do in a screening
programme?" using validation data from a high-prevalence clinical sample.
An epibyhand_derivation.
Altman, D. G. and Bland, J. M. (1994). Diagnostic tests 2: predictive values. BMJ, 309, 102.
# A test with 90% sensitivity and 90% specificity, 5% prevalence scr <- epi2x2(90, 180, 10, 1720, exposure = c("Test positive", "Test negative"), outcome = c("Diseased", "Healthy")) predictive_value(scr) predictive_value(scr, which = "negative") # The same test in a population where 40% are diseased predictive_value(scr, prevalence = 0.40)# A test with 90% sensitivity and 90% specificity, 5% prevalence scr <- epi2x2(90, 180, 10, 1720, exposure = c("Test positive", "Test negative"), outcome = c("Diseased", "Healthy")) predictive_value(scr) predictive_value(scr, which = "negative") # The same test in a population where 40% are diseased predictive_value(scr, prevalence = 0.40)
Print stratified tables
## S3 method for class 'epi_strata' print(x, indent = "", ...)## S3 method for class 'epi_strata' print(x, indent = "", ...)
x |
An |
indent |
Character prefix for each line. |
... |
Unused. |
x, invisibly.
Print a 2 x 2 table with margins
## S3 method for class 'epi2x2' print(x, indent = "", ...)## S3 method for class 'epi2x2' print(x, indent = "", ...)
x |
An |
indent |
Character prefix for each line. |
... |
Unused. |
x, invisibly.
Print a worked derivation
## S3 method for class 'epibyhand_derivation' print(x, verbose = NULL, digits = NULL, ...)## S3 method for class 'epibyhand_derivation' print(x, verbose = NULL, digits = NULL, ...)
x |
An |
verbose |
Detail level. |
digits |
Decimal places. Set globally with
|
... |
Unused. |
x, invisibly.
Risk difference with worked derivation
risk_difference(x, ..., conf_level = 0.95)risk_difference(x, ..., conf_level = 0.95)
x |
An |
... |
Further cell counts if |
conf_level |
Confidence level for the interval. |
An epibyhand_derivation.
risk_difference(epi2x2(36, 14, 30, 25))risk_difference(epi2x2(36, 14, 30, 25))
Risk ratio with worked derivation
risk_ratio(x, ..., conf_level = 0.95)risk_ratio(x, ..., conf_level = 0.95)
x |
An |
... |
Further cell counts if |
conf_level |
Confidence level for the interval. |
An epibyhand_derivation.
risk_ratio(epi2x2(36, 14, 30, 25))risk_ratio(epi2x2(36, 14, 30, 25))
Useful for building answer keys, or for rendering the derivation in a format this package does not provide.
steps_table(x)steps_table(x)
x |
An |
A data frame with one row per step.