-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathREADME.Rmd
More file actions
332 lines (246 loc) · 10.3 KB
/
README.Rmd
File metadata and controls
332 lines (246 loc) · 10.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
---
output: github_document
---
<!-- README.md is generated from README.Rmd. Please edit that file -->
```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "100%"
)
```
# riskdiff <img src="man/figures/logo.png" align="right" height="139"/>
<!-- badges: start -->
[](https://CRAN.R-project.org/package=riskdiff)
[](https://CRAN.R-project.org/package=riskdiff)
[](https://lifecycle.r-lib.org/articles/stages.html#stable)
[](https://github.com/jackmurphy2351/riskdiff/actions/workflows/R-CMD-check.yaml)
[](https://app.codecov.io/gh/jackmurphy2351/riskdiff?branch=main)
<!-- badges: end -->
The **riskdiff** package provides robust methods for calculating risk differences (also known as prevalence differences in cross-sectional studies) using generalized linear models with automatic link function selection and **boundary detection**.
## ✨ Now Available on CRAN!
**riskdiff** v0.2.1 is now published on CRAN with cutting-edge boundary detection capabilities that identify when maximum likelihood estimates lie at the edge of the parameter space - a common issue with identity link models that other packages ignore.
## Features
- **🎯 Smart boundary detection**: Automatically detects when GLMs hit parameter constraints
- **🔧 Robust model fitting**: Tries identity, log, and logit links with graceful fallback
- **📊 Stratified analysis**: Support for multi-level stratification
- **📋 Publication-ready output**: Formatted tables and confidence intervals
- **🛡️ Missing data handling**: Graceful handling of incomplete cases
- **⚙️ Flexible confidence intervals**: Robust methods for boundary cases
- **📈 Multiple link functions**: Automatic selection with boundary-aware switching
- **🔍 Transparent diagnostics**: Clear reporting of model methods and boundary issues
## Author
**John D. Murphy, MPH, PhD** ORCID: [0000-0002-7714-9976](https://orcid.org/0000-0002-7714-9976)
## Installation
### CRAN (Stable Release)
Install the latest stable version from CRAN:
```r
install.packages("riskdiff")
```
### Development Version
You can install the development version from [GitHub](https://github.com/) with:
```r
# install.packages("devtools")
devtools::install_github("jackmurphy2351/riskdiff")
```
## Quick Start
```{r example}
library(riskdiff)
# Load example data
data(cachar_sample)
# Simple risk difference with boundary detection
result <- calc_risk_diff(
data = cachar_sample,
outcome = "abnormal_screen",
exposure = "smoking"
)
print(result)
```
## 🎯 Boundary Detection in Action
```{r boundary-example}
# Create data that challenges standard GLM methods
set.seed(123)
challenging_data <- data.frame(
outcome = c(rep(0, 40), rep(1, 60)), # High baseline risk
exposure = factor(c(rep("No", 50), rep("Yes", 50))),
age = rnorm(100, 45, 10)
)
# riskdiff handles this gracefully with boundary detection
result <- calc_risk_diff(
data = challenging_data,
outcome = "outcome",
exposure = "exposure",
adjust_vars = "age",
verbose = TRUE # Shows diagnostic information
)
print(result)
# Check if boundary cases were detected
if (any(result$on_boundary)) {
cat("\n🚨 Boundary case detected! Using robust inference methods.\n")
cat("Boundary type:", unique(result$boundary_type[result$on_boundary]), "\n")
cat("CI method:", unique(result$ci_method[result$on_boundary]), "\n")
}
```
## Key Functions
### Basic Usage with Enhanced Diagnostics
```{r basic}
# Age-adjusted risk difference with boundary detection
rd_adjusted <- calc_risk_diff(
data = cachar_sample,
outcome = "abnormal_screen",
exposure = "smoking",
adjust_vars = "age",
boundary_method = "auto" # Automatic robust method selection
)
print(rd_adjusted)
```
### Stratified Analysis with Boundary Awareness
```{r stratified}
# Stratified by residence with boundary detection
rd_stratified <- calc_risk_diff(
data = cachar_sample,
outcome = "abnormal_screen",
exposure = "smoking",
adjust_vars = "age",
strata = "residence"
)
print(rd_stratified)
# Summary of boundary cases across strata
boundary_summary <- rd_stratified[rd_stratified$on_boundary,
c("residence", "boundary_type", "ci_method")]
if (nrow(boundary_summary) > 0) {
cat("\nBoundary cases by stratum:\n")
print(boundary_summary)
}
```
### Table Creation with Boundary Indicators
```{r tables}
# Create a simple text table with boundary information
cat(create_simple_table(rd_stratified, "Risk by Smoking Status and Residence"))
```
```{r tables-kable, eval=FALSE}
# Create publication-ready table (requires kableExtra)
library(kableExtra)
create_rd_table(rd_stratified,
caption = "Risk of Abnormal Screening Result by Smoking Status",
include_model_type = TRUE)
```
## 🧠 Statistical Methodology
### GLM Approach with Boundary Detection
The package uses generalized linear models with different link functions:
1. **Identity link** (preferred): Directly estimates risk differences
2. **Log link**: Estimates relative risks, transforms to risk differences
3. **Logit link**: Estimates odds ratios, transforms to risk differences
**Key Innovation**: When models hit parameter space boundaries (common with identity links), the package:
- 🔍 **Detects boundary cases** automatically
- ⚠️ **Warns users** about potential inference issues
- 🛡️ **Uses robust confidence intervals** when appropriate
- 📊 **Reports methodology transparently**
### Boundary Detection Types
- **Upper bound**: Fitted probabilities near 1 (risk saturation)
- **Lower bound**: Fitted probabilities near 0 (risk floor)
- **Separation**: Complete/quasi-separation in logistic models
- **Both bounds**: Multiple boundary issues detected
## Advanced Features
### Boundary Method Control
```{r boundary-methods}
# Force specific boundary handling
rd_conservative <- calc_risk_diff(
cachar_sample,
"abnormal_screen",
"smoking",
boundary_method = "auto" # Options: "auto", "profile", "wald"
)
# Check which methods were used
table(rd_conservative$ci_method)
```
### Link Function Selection with Boundary Awareness
```{r links}
# Force a specific link function
rd_logit <- calc_risk_diff(
cachar_sample,
"abnormal_screen",
"smoking",
link = "logit"
)
# Check which model was used and if boundaries detected
cat("Model used:", rd_logit$model_type, "\n")
cat("Boundary detected:", rd_logit$on_boundary, "\n")
```
### Confidence Intervals with Robust Methods
```{r confidence}
# 90% confidence intervals with boundary detection
rd_90 <- calc_risk_diff(
cachar_sample,
"abnormal_screen",
"smoking",
alpha = 0.10 # 1 - 0.10 = 90% CI
)
print(rd_90)
# The package automatically uses appropriate CI methods for boundary cases
```
## 📊 Understanding Results
### Enhanced Result Structure
```{r result-structure}
# Examine the enhanced result structure
data(cachar_sample)
result <- calc_risk_diff(cachar_sample, "abnormal_screen", "smoking")
names(result)
# Key columns:
# - on_boundary: Was a boundary case detected?
# - boundary_type: What type of boundary?
# - boundary_warning: Detailed diagnostic message
# - ci_method: Which CI method was used?
```
## Example Dataset
The package includes a realistic simulated cancer screening dataset:
```{r dataset}
data(cachar_sample)
str(cachar_sample)
# Summary statistics showing realistic associations
table(cachar_sample$smoking, cachar_sample$abnormal_screen)
# Risk difference analysis
rd_analysis <- calc_risk_diff(cachar_sample, "abnormal_screen", "smoking")
cat("Smoking increases risk of abnormal screening result by",
sprintf("%.1f", rd_analysis$rd * 100), "percentage points\n")
```
## When to Use Risk Differences
Risk differences are particularly valuable when:
- **Policy decisions**: You need the absolute impact size
- **Clinical practice**: Communicating real-world effect sizes
- **Common outcomes**: When outcome prevalence > 10%
- **Causal inference**: For intervention planning
- **Public health**: When relative measures can mislead
## Comparison with Other Measures
| Measure | Interpretation | Best When | riskdiff Advantage |
|---------|---------------|-----------|-------------------|
| **Risk Difference** | Absolute change in risk | Common outcomes, policy | **Boundary detection** |
| Risk Ratio | Relative change in risk | Rare outcomes | Standard methods only |
| Odds Ratio | Change in odds | Case-control studies | Standard methods only |
## 🔬 Statistical Foundation
This package implements methods based on:
- **Donoghoe & Marschner (2018)** - Robust GLM fitting methods for log-binomial models
- **Marschner & Gillett (2012)** - Boundary detection for log-binomial models
- **Rothman, Greenland & Lash (2008)** - Modern epidemiological methods
- **Austin (2011)** - Propensity score methods for causal inference
- **Hernán & Robins (2020)** - Causal inference methodology
## Getting Help
- 📖 **Vignettes**: `browseVignettes("riskdiff")`
- 🐛 **Bug reports**: [GitHub Issues](https://github.com/jackmurphy2351/riskdiff/issues)
- 💡 **Feature requests**: [GitHub Issues](https://github.com/jackmurphy2351/riskdiff/issues)
- 📧 **Questions**: Use GitHub Discussions
- 📋 **CRAN page**: [https://CRAN.R-project.org/package=riskdiff](https://CRAN.R-project.org/package=riskdiff)
## Citation
If you use this package in your research, please cite:
```r
citation("riskdiff")
```
## Related Packages
- **epitools**: Basic epidemiological calculations (no boundary detection)
- **epi**: Extended epidemiological functions (no boundary detection)
- **fmsb**: Medical statistics and epidemiology (no boundary detection)
- **Epi**: Statistical analysis in epidemiology (no boundary detection)
**riskdiff uniquely provides boundary detection for robust inference!**
## Code of Conduct
Please note that the riskdiff project is released with a [Contributor Code of Conduct](https://contributor-covenant.org/version/2/1/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms.