tipr
tipr: An R package for sensitivity analyses for unmeasured confounders - Published in JOSS (2022)
Science Score: 49.0%
This score indicates how likely this project is to be science-related based on various indicators:
-
○CITATION.cff file
-
✓codemeta.json file
Found codemeta.json file -
✓.zenodo.json file
Found .zenodo.json file -
✓DOI references
Found 3 DOI reference(s) in README -
✓Academic publication links
Links to: joss.theoj.org -
○Committers with academic emails
-
○Institutional organization owner
-
○JOSS paper metadata
-
○Scientific vocabulary similarity
Low similarity (15.3%) to scientific vocabulary
Scientific Fields
Earth and Environmental Sciences
Physical Sciences -
40% confidence
Medicine
Life Sciences -
40% confidence
Engineering
Computer Science -
40% confidence
Last synced: 4 months ago
·
JSON representation
Repository
An R package for conducting sensitivity analyses for unmeasured confounders
Basic Info
- Host: GitHub
- Owner: r-causal
- License: other
- Language: R
- Default Branch: master
- Homepage: https://r-causal.github.io/tipr/
- Size: 5.46 MB
Statistics
- Stars: 41
- Watchers: 4
- Forks: 4
- Open Issues: 1
- Releases: 8
Created almost 9 years ago
· Last pushed almost 2 years ago
Metadata Files
Readme
Changelog
License
Code of conduct
README.Rmd
--- output: github_document --- # tipr: R tools for tipping point sensitivity analyses[](https://github.com/r-causal/tipr/actions) [](https://doi.org/10.21105/joss.04495) **Authors:** [Lucy D'Agostino McGowan](https://www.lucymcgowan.com/), [Malcolm Barrett](https://malco.io/)
**License:** [MIT](https://opensource.org/license/mit/) ## Installation Install the CRAN version ```{r, eval = FALSE} install.packages("tipr") ``` Or install the development version from GitHub: ```{r, eval = FALSE} # install.packages(devtools) devtools::install_github("r-causal/tipr") ``` ```{r} library(tipr) ``` ## Usage After fitting your model, you can determine the unmeasured confounder needed to tip your analysis. This unmeasured confounder is determined by two quantities, the relationship between the exposure and the unmeasured confounder (if the unmeasured confounder is continuous, this is indicated with `exposure_confounder_effect`, if binary, with `exposed_confounder_prev` and `unexposed_confounder_prev`), and the relationship between the unmeasured confounder and outcome `confounder_outcome_effect`. Using this `r emo::ji("package")`, we can fix one of these and solve for the other. Alternatively, we can fix both and solve for `n`, that is, how many unmeasured confounders of this magnitude would tip the analysis. This package comes with a few example data sets. For this example, we will use `exdata_rr`. This data set was simulated such that there are two confounders, one that was "measured" (and thus usable in the main analysis, this is called `measured_confounder`) and one that is "unmeasured" (we have access to it because this is simulated data, but ordinarily we would not, this variable is called `.unmeasured_confounder`). Using the example data `exdata_rr`, we can estimate the exposure-outcome relationship using the measured confounder as follows: ```{r} mod <- glm(outcome ~ exposure + measured_confounder, data = exdata_rr, family = poisson) mod |> broom::tidy(exponentiate = TRUE, conf.int = TRUE) ``` We see the above example, the exposure-outcome relationship is 1.5 (95% CI: 1.1, 2.1). Note, in practice when estimating the effect of an exposure on a binary outcome using a GLM with the Poisson distribution and log link function, it is important to use a sandwich estimator to appropriately estimate the variability (this can be done in R using the `sandwich` package), which in this case gives a very similar result (95% CI: 1.1, 2.0). ## Continuous unmeasured confounder example We are interested in a continuous unmeasured confounder, so we will use the `tip_with_continuous()` function. Let's assume the unmeasured confounder is normally distributed with a mean of 0.5 in the exposed group and 0 in the unexposed (and unit variance in both), resulting in a mean difference of 0.5 (`exposure_confounder_effect = 0.5`), let's solve for the relationship between the unmeasured confounder and outcome needed to tip the analysis (in this case, we are solving for `confounder_outcome_effect`). ```{r} tip(effect_observed = 1.5, exposure_confounder_effect = 0.5) ``` A hypothetical unobserved continuous confounder a scaled mean difference between exposure groups of `0.5` would need a relationship of at least 2.25 with the outcome to tip this analysis at the point estimate. ```{r} tip(effect_observed = 1.09, exposure_confounder_effect = 0.5) ``` A hypothetical unobserved continuous confounder a scaled mean difference between exposure groups of `0.5` would need a relationship of at least 1.19 with the outcome to tip this analysis at the 5% level, rendering it inconclusive. Because this is simulated data, we can see what the *true* unmeasured confounder looked like. First we will calculate the difference in scaled means. ```{r} exdata_rr |> dplyr::group_by(exposure) |> dplyr::summarise(m = mean(.unmeasured_confounder / sd(.unmeasured_confounder))) |> tidyr::pivot_wider(names_from = exposure, values_from = m, names_prefix = "u_") |> dplyr::summarise(estimate = u_1 - u_0) ``` Now we can refit the above model with this unmeasured confounder included. According to our tipping point result, as long as the risk ratio of the unmeasured confounder and outcome in the model is greater than 2.25, the result that we observed will be "tipped" (the point estimate will cross the null). ```{r} mod_true <- glm( outcome ~ exposure + measured_confounder + .unmeasured_confounder, data = exdata_rr, family = poisson) mod_true |> broom::tidy(exponentiate = TRUE, conf.int = TRUE) ``` Notice here the `.unmeasured_confounder` effect is 2.42 (which is greater than the 2.25 we calculated that would be needed to render our result null) and, as expected, the point estimate for the `exposure` has crossed the null (and now is less than 1). ## Binary unmeasured confounder example Now we are interested in the binary unmeasured confounder, so we will use the `tip_with_binary()` function. Let's assume the unmeasured confounder is prevalent in 25% of the exposed population (`exposed_confounder_prev = 0.25`) and in 10% of the unexposed population (`unexposed_confounder_prev = 0.10`) -- let's solve for the relationship between the unmeasured confounder and the outcome needed to tip the analysis (`confounder_outcome_effect`). ```{r} tip_with_binary(effect_observed = 1.09, exposed_confounder_prev = 0.25, unexposed_confounder_prev = 0.10) ``` A hypothetical unobserved binary confounder that is prevalent in 10% of the unexposed population and 25% of the exposed population would need to have a relationship with the outcome of 1.64 to tip this analysis at the 5% level, rendering it inconclusive. ## Many unmeasured confounders Suppose we are concerned that there are many small, independent, continuous, unmeasured confounders present. ```{r} tip(effect_observed = 1.09, exposure_confounder_effect = 0.25, confounder_outcome_effect = 1.05) ``` It would take about `7` independent standardized Normal unmeasured confounders with a mean difference between exposure groups of 0.25 and a relationship with the outcome of 1.05 tip the observed analysis at the 5% level, rendering it inconclusive. ## Integration with broom These functions were created to easily integrate with models tidied using the **broom** package. This is not _necessary_ to use these functions, but a nice feature if you choose to do so. Here is an example of a logistic regression fit with `glm` and tidied with the `tidy` function **broom** that can be directly fed into the `tip()` function. ```{r} if (requireNamespace("broom", quietly = TRUE) && requireNamespace("dplyr", quietly = TRUE)) { glm(outcome ~ exposure + measured_confounder, data = exdata_rr, family = poisson) |> broom::tidy(conf.int = TRUE, exponentiate = TRUE) |> dplyr::filter(term == "exposure") |> dplyr::pull(conf.low) |> tip(confounder_outcome_effect = 2.5) } ``` ## Code of Conduct Please note that the tipr project is released with a [Contributor Code of Conduct](https://contributor-covenant.org/version/2/0/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms.
Owner
- Name: r-causal
- Login: r-causal
- Kind: organization
- Repositories: 1
- Profile: https://github.com/r-causal
GitHub Events
Total
- Watch event: 8
- Fork event: 2
Last Year
- Watch event: 8
- Fork event: 2
Committers
Last synced: 5 months ago
Top Committers
| Name | Commits | |
|---|---|---|
| Lucy D'Agostino McGowan | l****o@g****m | 118 |
| Malcolm Barrett | m****t@g****m | 20 |
Issues and Pull Requests
Last synced: 4 months ago
All Time
- Total issues: 2
- Total pull requests: 3
- Average time to close issues: 3 days
- Average time to close pull requests: 9 days
- Total issue authors: 2
- Total pull request authors: 2
- Average comments per issue: 3.5
- Average comments per pull request: 0.33
- Merged pull requests: 2
- Bot issues: 0
- Bot pull requests: 0
Past Year
- Issues: 0
- Pull requests: 0
- Average time to close issues: N/A
- Average time to close pull requests: N/A
- Issue authors: 0
- Pull request authors: 0
- Average comments per issue: 0
- Average comments per pull request: 0
- Merged pull requests: 0
- Bot issues: 0
- Bot pull requests: 0
Top Authors
Issue Authors
- LucyMcGowan (1)
- malcolmbarrett (1)
Pull Request Authors
- malcolmbarrett (4)
- olivroy (2)
Top Labels
Issue Labels
Pull Request Labels
Packages
- Total packages: 1
-
Total downloads:
- cran 419 last-month
- Total dependent packages: 0
- Total dependent repositories: 2
- Total versions: 8
- Total maintainers: 1
cran.r-project.org: tipr
Tipping Point Analyses
- Homepage: https://r-causal.github.io/tipr/
- Documentation: http://cran.r-project.org/web/packages/tipr/tipr.pdf
- License: MIT + file LICENSE
-
Latest release: 1.0.2
published almost 2 years ago
Rankings
Stargazers count: 9.5%
Forks count: 17.1%
Dependent repos count: 19.3%
Average: 21.1%
Dependent packages count: 28.8%
Downloads: 30.7%
Maintainers (1)
Last synced:
4 months ago
Dependencies
DESCRIPTION
cran
- R >= 2.10 depends
- glue * imports
- purrr * imports
- sensemakr * imports
- tibble * imports
- MASS * suggests
- broom * suggests
- dplyr * suggests
- testthat * suggests
.github/workflows/R-CMD-check.yaml
actions
- actions/checkout v2 composite
- r-lib/actions/check-r-package v2 composite
- r-lib/actions/setup-pandoc v2 composite
- r-lib/actions/setup-r v2 composite
- r-lib/actions/setup-r-dependencies v2 composite
.github/workflows/pkgdown.yaml
actions
- JamesIves/github-pages-deploy-action v4.4.1 composite
- actions/checkout v3 composite
- r-lib/actions/setup-pandoc v2 composite
- r-lib/actions/setup-r v2 composite
- r-lib/actions/setup-r-dependencies v2 composite
[](https://github.com/r-causal/tipr/actions)
[](https://doi.org/10.21105/joss.04495)
**Authors:** [Lucy D'Agostino McGowan](https://www.lucymcgowan.com/), [Malcolm Barrett](https://malco.io/)