Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package: discord
Type: Package
Title: Functions for Discordant Kinship Modeling
Version: 1.2.4.1
Version: 1.3
Authors@R: c(person("S. Mason", "Garrison", email = "garrissm@wfu.edu",
role = c("aut", "cre", "cph"),
comment = c(ORCID = "0000-0002-4804-6003")),
Expand All @@ -11,7 +11,7 @@ Authors@R: c(person("S. Mason", "Garrison", email = "garrissm@wfu.edu",
person("Yoo Ri", "Hwang", email = "yrhwang89@gmail.com",
role = "aut"),
person("Cermet", "Ream", role = c("ctb")))
Description: Functions for discordant kinship modeling (and other sibling-based quasi-experimental designs). Contains data restructuring functions and functions for generating biometrically informed data for kin pairs. See [Garrison and Rodgers, 2016 <doi:10.1016/j.intell.2016.08.008>], [Sims, Trattner, and Garrison, 2024 <doi:10.3389/fpsyg.2024.1430978>] for empirical examples, and Garrison and colleagues for theoretical work <doi.org/10.1101/2025.08.25.25334395>.
Description: Functions for discordant kinship modeling (and other sibling-based quasi-experimental designs). Contains data restructuring functions and functions for generating biometrically informed data for kin pairs. See [Garrison and Rodgers, 2016 <doi:10.1016/j.intell.2016.08.008>], [Sims, Trattner, and Garrison, 2024 <doi:10.3389/fpsyg.2024.1430978>] for empirical examples, and [Garrison and colleagues for theoretical work <doi.org/10.1101/2025.08.25.25334395>].
URL: https://github.com/R-Computing-Lab/discord,
https://r-computing-lab.github.io/discord/
License: GPL-3
Expand All @@ -36,9 +36,11 @@ Suggests:
magrittr,
rmarkdown,
scales,
sessioninfo,
stargazer,
snakecase,
testthat,
tidyverse
tidyverse,
tidyr
VignetteBuilder:
knitr
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
# discord 1.3
* Adding new full data tutorial in response to reviewers
* Adding links to external repositories for reproducible examples from publications
* Added smarter id handling to `discord_data()`
* Added more tests to legacy comparisons and ids

# discord 1.2.4.1
* Added a new vignette demonstrating ways to visualize discordant kinship data using the `ggplot2` package.
* Added a new vignette demonstrating how to conduct a power analysis.
* Vectorizing `discord_data()` to improve performance.
* Adding tests to ensure comparability between optimized and non-optimized versions of `discord_data()`.
* Adding `discord_between_model()` to get the between-family model
* Adding `discord_within_model()` to get the within-family model
* Added unique filter for `discord_data()` to ensure that the data is not duplicated.
* Added tests for categorical variables in `discord_data()`.
* Added hotfix to BGmisc vignette.
Expand Down
14 changes: 7 additions & 7 deletions R/func_discord_data.R
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,12 @@ discord_data <- function(data,
id = NULL,
sex = "sex",
race = "race",
pair_identifiers = c("_s1","_s2"),
pair_identifiers = c("_s1", "_s2"),
demographics = "both",
coding_method = "none",
fast = TRUE,
...) {


if (fast==TRUE) {
if (fast == TRUE) {
unique(discord_data_fast(
data = data,
outcome = outcome,
Expand Down Expand Up @@ -224,10 +222,12 @@ discord_data_fast <- function(data,
if (!valid_ids(orderedOnOutcome,
id = id
)) {
id_orginal <- id
id_original <- id
id <- "rowwise_id"
orderedOnOutcome <- cbind(orderedOnOutcome, id_orginal = data[id_orginal],
rowwise_id = 1:nrow(data))
orderedOnOutcome <- cbind(orderedOnOutcome,
id_original = data[id_original],
rowwise_id = 1:nrow(data)
)
}

#-------------------------------------------
Expand Down
17 changes: 14 additions & 3 deletions R/func_kinsim.R
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#' @param cov_a Numeric. Shared variance for additive genetics between variables; default is 0.
#' @param cov_c Numeric. Shared variance for shared-environment between variables; default is 0.
#' @param cov_e Numeric. Shared variance for non-shared-environment between variables; default is 0.
#' @param id Numeric vector. Optional unique identifiers for each kinship pair;
#' @param ... Additional arguments passed to other methods.

#' @return A data frame with the following columns:
Expand Down Expand Up @@ -87,6 +88,7 @@ kinsim <- function(
cov_a = 0, # default shared covariance for genetics across variables
cov_c = 0, # default shared variance for c across variables
cov_e = 0, # default shared variance for e across variables
id = NULL,
...) {
# Check if the number of rows in ace_list matches the number of variables
mu <- NULL
Expand All @@ -103,7 +105,10 @@ kinsim <- function(
npergroup = npergroup_all, #
mu = mu_list[1], # intercept
ace = ace_list[1, ],
r_vector = r_vector
r_vector = r_vector,
c_vector = c_vector,
id = id,
...
)
data_v$A1_u <- data_v$A1
data_v$A2_u <- data_v$A2
Expand All @@ -123,7 +128,10 @@ kinsim <- function(
stop("You have tried to generate data beyond the current limitations of this program. Maximum variables 2.")
}
if (is.null(r_vector)) {
id <- 1:sum(npergroup_all)
if(is.null(id)){
id <- 1:sum(npergroup_all)
}

for (i in 1:length(r_all)) {
n <- npergroup_all[i]

Expand Down Expand Up @@ -200,7 +208,10 @@ kinsim <- function(
merged.data.frame <- Reduce(function(...) merge(..., all = TRUE), datalist)
merged.data.frame$id <- id
} else {
id <- seq_along(r_vector)
if(is.null(id)){
id <- seq_along(r_vector)
}

# Initialize full-length empty matrices
n <- length(r_vector)
A.r <- matrix(NA_real_, nrow = n, ncol = 4)
Expand Down
2 changes: 1 addition & 1 deletion R/helpers_regression.R
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ make_mean_diffs_ram_optimized <- function(data, id, sex, race, demographics,
recode_demographics <- function(demographics, data, raceS1, raceS2,
race, sexS1, sexS2, sex, coding_method, output, fast = FALSE) {
# check for whether or not race and sex are defined
if (fast==TRUE) {
if (fast == TRUE) {
if (demographics == "race") {
output_demographics <- data.frame(
race_1 = data[[raceS1]],
Expand Down
15 changes: 12 additions & 3 deletions R/helpers_simulation.R
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@
#' a = additive genetic, c = shared environment, e = non-shared environment;
#' default is c(1, 1, 1).
#' @param r_vector Numeric vector. Alternative specification method providing relatedness
#' coefficients for the entire sample; default is NULL.
#' coefficients for the entire sample; default is NULL. If provided, \code{r_vector} overrides \code{r} and \code{npergroup}.
#' @param c_vector Numeric vector. Optional vector of shared environmental correlations. for each kinship pair. If provided, \code{c_vector} overrides \code{c_rel} and \code{npergroup}. The length of \code{c_vector} must match that of \code{r_vector} (if provided), or the total number of pairs implied by \code{r} and \code{npergroup}. Values should be in the range [0, 1].
#' @param id Numeric vector. Optional unique identifiers for each kinship pair;
#' default is NULL, in which case IDs are assigned sequentially.
#' @param ... Additional arguments passed to other methods.
#' @keywords internal
#' @return A data frame with the following columns:
Expand Down Expand Up @@ -66,6 +69,7 @@ kinsim_internal <- function(
ace = c(1, 1, 1),
r_vector = NULL,
c_vector = NULL,
id = NULL,
...) {
# Calculate standard deviations from variance components
sA <- ace[1]^0.5
Expand All @@ -85,7 +89,10 @@ kinsim_internal <- function(

# Handle standard case with groups of different relatedness
if (is.null(r_vector)) {
id <- 1:sum(npergroup)

if(is.null(id)){
id <- 1:sum(npergroup)
}


# Generate data for each relatedness group
Expand Down Expand Up @@ -129,7 +136,9 @@ kinsim_internal <- function(
merged.data.frame$id <- id
} else {
# Handle case with custom relatedness vector
id <- 1:length(r_vector)
if(is.null(id)){
id <- 1:length(r_vector)
}

data_vector <- data.frame(id, r_vector)
data_vector$A.r1 <- as.numeric(NA)
Expand Down
10 changes: 6 additions & 4 deletions R/legacy.R
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ discord_data_legacy <- function(

if (!doubleentered) {
outcome2x <- outcome2
outcome2 <- c(outcome2[, 1], outcome1[, 1])
outcome1 <- c(outcome1[, 1], outcome2x[, 1])
outcome2 <- c(outcome2, outcome1) #c(outcome2[, 1], outcome1[, 1])
outcome1 <- c(outcome1, outcome2x) # c(outcome1[, 1], outcome2x[, 1])

if (scale & is.numeric(outcome1)) {
outcome1 <- scale(outcome1)
Expand All @@ -78,8 +78,10 @@ discord_data_legacy <- function(
for (i in 1:length(predictors)) {
predictor1x <- predictor1 <- subset(df, select = paste0(predictors[i], sep, "1"))[, 1]
predictor2 <- subset(df, select = paste0(predictors[i], sep, "2"))[, 1]
predictor1 <- c(predictor1[, 1], predictor2[, 1])
predictor2 <- c(predictor2[, 1], predictor1x[, 1])
predictor1 <- c(predictor1, predictor2)
#c(predictor1[, 1], predictor2[, 1])
predictor2 <- c(predictor2, predictor1x)
#c(predictor2[, 1], predictor1x[, 1])
if (scale & is.numeric(predictor1)) {
predictor1 <- scale(predictor1)
predictor2 <- scale(predictor2)
Expand Down
145 changes: 133 additions & 12 deletions README.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ knitr::opts_chunk$set(
# discord

<!-- badges: start -->
<a href="https://r-computing-lab.github.io/discord/"><img src="man/figures/logo.png" align="right" height="139" alt="discord website" /></a>
<a href="https://r-computing-lab.github.io/discord/"><img src="man/figures/logo.png" alt="discord website" align="right" height="139"/></a>
[![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active)
[![R package version](https://www.r-pkg.org/badges/version/discord)](https://cran.r-project.org/package=discord)
[![Package downloads](https://cranlogs.r-pkg.org/badges/grand-total/discord)](https://cran.r-project.org/package=discord)</br>
Expand All @@ -27,11 +27,121 @@ knitr::opts_chunk$set(

<!-- badges: end -->

The goal of discord is to provide functions for discordant kinship
modeling and other sibling-based quasi-experimental designs. It has
highly customizable, efficient code for generating genetically-informed
simulations and provides user-friendly functions to perform
discordant-kinship regressions.
`discord` is an R package that provides functions for discordant kinship
modeling and other sibling-based quasi-experimental designs. It includes
functions for data preparation, regression analysis, and simulation of
genetically-informed data. The package is designed to facilitate the
implementation of discordant sibling designs in research, allowing for
the control of shared familial confounding factors.

Visit the [discord website](https://r-computing-lab.github.io/discord/)
for more information and detailed documentation. Below is a brief
overview of the package, its features, and vignettes to get you started.

## Features

- **Data Preparation**: Functions to prepare and structure data for
discordant sibling analysis, including handling of kinship pairs and
demographic variables.
- **Regression Analysis**: Tools to perform discordant regression
analyses, allowing for the examination of within-family effects
while controlling for shared familial confounders.
- **Simulation**: Functions to simulate genetically-informed data,
enabling researchers to test and validate their models.

## Vignettes

The package includes several vignettes to help users understand and
utilize its features effectively. These vignettes can be accessed
[online](https://r-computing-lab.github.io/discord/articles/) or by
selecting them from the RStudio "Vignettes" tab after installing the
package.

The following vignettes are available:

- [Power Analysis with discord](https://r-computing-lab.github.io/discord/articles/Power.html)
- Use this vignette when you need to plan sample sizes or evaluate
detectability by running simulation grids that vary effect
sizes, kin types, and Ns using kinsim, then re-fitting
discord_regression under each condition. It reports empirical
power, writes tidy summaries, and includes code to visualize
power curves across conditions to support design decisions.

- [Regression Analysis with discord](https://r-computing-lab.github.io/discord/articles/regression.html)
- Use this if you want an end-to-end applied example that links
NLSY79 relatives, cleans variables for flu vaccination and SES,
constructs dyads, and then fits within-family models. You will
learn how to specify discord_regression correctly and interpret
coefficients when predictors vary within pairs versus only
between pairs.

- [Handling Categorical Predictors](https://r-computing-lab.github.io/discord/articles/categorical_predictors.html)
- This vignette formalizes categorical predictors in discord
designs by separating mixed from between-dyad variables and
making the implied contrasts explicit. It implements
binary-match and multi-category match encodings on concrete
examples (e.g., sex, race), fits the corresponding
discord_regression specifications, and contrasts estimates to
show how encoding choices change interpretation.

- [Full Data Workflow](https://r-computing-lab.github.io/discord/articles/full_data_workflow.html)
- Starting from raw wide and long person-level inputs, this
vignette builds kin links, aligns IDs, and constructs the
discord_data object with sibling-specific columns ready for
modeling. It then fits a conventional between-family regression
alongside a discord model on the same variables, so you can see
where the within-family estimate diverges and adopt the pipeline
as a template.

- [Creating Plots](https://r-computing-lab.github.io/discord/articles/plots.html)
- This vignette takes fitted discord_regression outputs and
produces publication-ready ggplot figures of effect estimates
and within-family contrasts with minimal transformation of the
model results. It includes complete plotting code paths you can
reuse, from extracting estimates to saving figures that clearly
communicate within-family findings.

- [No Database? No Problem: Using discord with Simple Family Structures](https://r-computing-lab.github.io/discord/articles/links.html)
- This vignette is particularly useful for situations when you do
not have existing kinship links and need to build link tables
directly from simple family identifiers. It shows how to
construct the links, optionally simulate phenotypes under
specified structures, and fit discord_regression with
alternative specifications for small or bespoke datasets.

## External Reproducible Examples

Beyond the vignettes, you can find additional examples that fully
reproduce analyses from our other publications (Garrison et al 2025,
etc). These examples can be accessed via the following links:

- National Longitudinal Survey of Youth (NLSY) dataset
- [Intelligence](https://github.com/R-Computing-Lab/Project_AFI_Intelligence):
Reproduces Garrison, S. M., & Rodgers, J. L. (2016). Casting
doubt on the causal link between intelligence and age at first
intercourse: A cross-generational sibling comparison design
using the NLSY. Intelligence, 59, 139-156.
<https://doi.org/10.1016/j.intell.2016.08.008>

- [Frontiers](https://github.com/R-Computing-Lab/Sims-et-al-2024):
Reproduces Sims, E. E., Trattner, J. D., & Garrison, S. M.
(2024). Exploring the relationship between depression and
delinquency: a sibling comparison design using the NLSY.
Frontiers in psychology, 15, 1430978.
<https://doi.org/10.3389/fpsyg.2024.1430978>

- [AMPPS](https://github.com/R-Computing-Lab/target-causalclaims):
Reproduces analyses from Garrison et al 2025, using `targets`
for workflow management. Garrison, S. M., Trattner, J. D., Lyu,
X., Prillaman, H. R., McKinzie, L., Thompson, S. H. E., &
Rodgers, J. L. (2025). Sibling Models Can Test Causal Claims
without Experiments: Applications for Psychology.
<https://doi.org/10.1101/2025.08.25.25334395>
- China Family Panel Studies (CFPS) dataset
- [AMPPS](https://github.com/R-Computing-Lab/discord_CFPS):
Reproduces analyses from the China Family Panel Studies (CFPS)
dataset, focusing on the association between adolescent
depression and math achievement.

## Installation

Expand All @@ -41,7 +151,9 @@ You can install the official version from CRAN
# Install/update discord with the release version from CRAN.
install.packages('discord')
```
You can also install/update discord with the development version of discord from [GitHub](https://github.com/) with:

You can also install/update discord with the development version of
discord from [GitHub](https://github.com/) with:

``` r
# If devtools is not installed, uncomment the line below.
Expand All @@ -51,15 +163,24 @@ devtools::install_github('R-Computing-Lab/discord')

## Citation

If you use `discord` in your research or wish to refer to it, please cite the following paper:
If you use `discord` in your research or wish to refer to it, please
cite the following paper:

```{r eval=TRUE, comment=NA}
```{r eval=TRUE, comment=NA,warning=FALSE, message=FALSE}
citation(package = "discord")
```


## Contributing
Contributions to the `discord` project are welcome. For guidelines on how to contribute, please refer to the [Contributing Guidelines](https://github.com/R-Computing-Lab/discord/blob/main/CONTRIBUTING.md). Issues and pull requests should be submitted on the GitHub repository. For support, please use the GitHub issues page.

Contributions to the `discord` project are welcome. For guidelines on
how to contribute, please refer to the [Contributing
Guidelines](https://github.com/R-Computing-Lab/discord/blob/main/CONTRIBUTING.md).
Issues and pull requests should be submitted on the GitHub repository.
For support, please use the GitHub issues page.

## License
`discord` is licensed under the GNU General Public License v3.0. For more details, see the [LICENSE](https://github.com/R-Computing-Lab/discord/blob/main/LICENSE) file.

`discord` is licensed under the GNU General Public License v3.0. For
more details, see the
[LICENSE](https://github.com/R-Computing-Lab/discord/blob/main/LICENSE)
file.
Loading