Skip to content
Open
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
717 changes: 717 additions & 0 deletions Estimating_Heritability.ipynb

Large diffs are not rendered by default.

89 changes: 89 additions & 0 deletions GREML.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": "# Topic: GCTA-GREML (Genomic Relatedness Restricted Maximum Likelihood)\n\n**Based on:** \n1. Yang et al. *Common SNPs explain a large proportion of the heritability for human height.* (Nature Genetics, 2010)\n2. Yang et al. *GCTA: A Tool for Genome-wide Complex Trait Analysis.* (AJHG, 2011)\n\n---\n\n# 1. Motivation and Graphical Summary\n\n## The Problem: \"Missing Heritability\"\nBefore 2010, Genome-Wide Association Studies (GWAS) faced a paradox. For traits like height, family studies (twins) showed heritability was high (~80%). However, when researchers summed up the effects of all statistically significant SNPs found in GWAS, they explained very little variance (only ~5%). \n\nWhere was the rest? Was it \"missing\"? Or was it hiding?\n\n## Why Simpler Approaches Fail\nStandard GWAS tests one SNP at a time (marginal regression). To avoid false positives among millions of tests, we use a strict significance threshold ($p < 5 \\times 10^{-8}$). \n- **The Limitation:** Most complex traits are **polygenic**—influenced by thousands of variants with tiny effects. These small effects do not pass the strict threshold, so standard GWAS ignores them.\n- **The GCTA Insight:** Instead of asking *\"Which specific SNPs are significant?\"*, GCTA asks: *\"If we look at ALL the SNPs together (the significant and the non-significant ones), how much phenotypic variation can we explain?\"*\n\n## Visual Summary\nThe core idea relies on **Realized Genomic Relatedness**. Even among \"unrelated\" people, some pairs share slightly more DNA than others. GCTA measures if people who are more genetically similar are also more phenotypically similar."
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": []
},
"outputs": [],
"source": "rm(list = ls())\nsuppressMessages(library(rrBLUP))\n\n# Graphical Summary Concept Plot\nset.seed(123)\npar(mfrow = c(1, 2), mar = c(5, 5, 4, 2))\n\n# 1. The GWAS view (The Tip of the Iceberg)\nbarplot(c(5, 80), names.arg = c(\"GWAS Hits\", \"Total Heritability\"), \n col = c(\"red\", \"lightgray\"), main = \"The Missing Heritability Problem\", \n ylab = \"Variance Explained (%)\",\n cex.main = 1.4, cex.lab = 1.3, cex.axis = 1.2, cex.names = 1.2)\n\n# 2. The GREML view (Regression on Relatedness)\ng_rel <- rnorm(100, mean = 0, sd = 0.01)\np_sim <- 0.5 * g_rel + rnorm(100, 0, 0.05)\nplot(g_rel, p_sim, pch = 19, col = \"blue\", cex = 1.2,\n xlab = \"Genomic Relatedness (A_jk)\", ylab = \"Phenotypic Similarity\", \n main = \"The GREML Solution\",\n cex.main = 1.4, cex.lab = 1.3, cex.axis = 1.2)\nabline(lm(p_sim ~ g_rel), col = \"red\", lwd = 3)\ntext(0, 0.02, \"Slope ≈ Heritability\", col = \"red\", cex = 1.2)"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "# 2. Key Assumptions and Generative Model\n\n## Assumptions (Yang et al., 2010)\n1. **Polygenicity:** The trait is influenced by a very large number of variants with small effects.\n2. **Random Effects:** We treat SNP effects as random variables drawn from a normal distribution, rather than fixed values to be estimated one by one.\n3. **LD Tagging:** Causal variants are in Linkage Disequilibrium (LD) with the SNPs on the genotyping chip. If a causal variant is not tagged by a SNP, GCTA cannot see it.\n4. **Unrelated Individuals:** The method requires samples to be distantly related (usually excluding cousins, relatedness < 0.025). This ensures we measure genetic effects, not shared family environment.\n\n## The Linear Mixed Model (LMM)\nInstead of the standard regression $y = X\\beta + \\epsilon$, we use:\n\n$$\ny = X\\beta + g + \\epsilon\n$$\n\nWhere:\n* $y$: Vector of phenotypes ($N \\times 1$)\n* $X\\beta$: Fixed effects (covariates like age, sex, population structure PCs)\n* $g$: Total genetic effect captured by all SNPs (Random Effect)\n* $\\epsilon$: Residual environmental error\n\n## The Generative Variance Structure\nWe assume the genetic effects follow a multivariate normal distribution defined by the **Genetic Relationship Matrix (GRM)**, denoted as $A$:\n\n$$\ng \\sim N(0, A\\sigma_g^2)\n$$\n\nThe total variance of the phenotype is:\n\n$$\nVar(y) = V = A\\sigma_g^2 + I\\sigma_e^2\n$$\n\nOur goal is to estimate $\\sigma_g^2$ (genetic variance) and $\\sigma_e^2$ (environmental variance)."
},
{
"cell_type": "markdown",
"metadata": {},
"source": "# 3. Inference Approaches and Methods\n\n## Step 1: Calculating the GRM ($A$)\nHow do we define genetic relatedness between \"unrelated\" people? We compare their genotypes across the whole genome. \n\nFrom **Equation 3 in Yang et al. (2011)**, the relationship between individual $j$ and $k$ is:\n\n$$\nA_{jk} = \\frac{1}{N_{snps}} \\sum_{i=1}^{N_{snps}} \\frac{(x_{ij} - 2p_i)(x_{ik} - 2p_i)}{2p_i(1 - p_i)}\n$$\n\n* $x_{ij}$: Genotype of person $j$ at SNP $i$ (coded 0, 1, 2).\n* $p_i$: Frequency of the reference allele at SNP $i$.\n* $2p_i(1-p_i)$: The expected variance of the SNP (standardization).\n\nThis formula calculates the average covariance between genotypes, standardized by allele frequency.\n\n## Step 2: REML (Restricted Maximum Likelihood)\nWe use REML instead of standard Maximum Likelihood (ML). \n* **Why?** Standard ML estimates of variance are biased because they treat fixed effects (like the mean or age) as known, ignoring the degrees of freedom lost estimating them.\n* **Algorithm:** GCTA uses the **Average Information (AI)** algorithm, an iterative procedure (Newton-Raphson type) to find the values of $\\sigma_g^2$ and $\\sigma_e^2$ that maximize the likelihood of the data given the matrix $A$."
},
{
"cell_type": "markdown",
"metadata": {},
"source": "# 4. Worked Example (R Simulation)\n\nWe will replicate the logic in R. We will simulate genotypes, build the GRM manually using the formula, and estimate heritability."
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": []
},
"outputs": [],
"source": "# --- 1. SIMULATION ---\nset.seed(2023)\nN <- 1000 # Number of individuals\nM <- 2000 # Number of SNPs\n\n# Generate Genotype Matrix X (0, 1, 2) - vectorized\nfreqs <- runif(M, 0.1, 0.5)\nX <- sapply(freqs, function(p) rbinom(N, 2, p))\n\n# Assign True Heritability\nh2_true <- 0.6\n\n# Generate Genetic Effects (g)\nu <- rnorm(M, mean = 0, sd = sqrt(1/M))\ng <- X %*% u\ng <- scale(g) * sqrt(h2_true)\n\n# Generate Environmental Error (e)\ne <- rnorm(N)\ne <- scale(e) * sqrt(1 - h2_true)\n\n# Create Phenotype\ny <- g + e\n\ncat(sprintf(\"Genotype matrix X: %d individuals x %d SNPs\\n\", nrow(X), ncol(X)))\ncat(sprintf(\"Phenotype variance: %.3f\\n\", var(as.vector(y))))\ncat(\"\\nGenotype matrix preview (first 5 individuals, first 8 SNPs):\\n\")\nprint(X[1:5, 1:8])"
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": []
},
"outputs": [],
"source": "# --- 2. CALCULATE GRM (Vectorized, Equation 3 from Yang 2011) ---\n\ncompute_GRM <- function(G) {\n # Allele frequencies\n p <- colMeans(G) / 2\n \n # Vectorized standardization: (x - 2p) / sqrt(2p(1-p))\n W <- sweep(G, 2, 2 * p) / sqrt(2 * p * (1 - p))\n \n # A = WW' / M\n A <- tcrossprod(W) / ncol(G)\n return(A)\n}\n\nA_est <- compute_GRM(X)\n\ncat(sprintf(\"GRM dimensions: %d x %d\\n\", nrow(A_est), ncol(A_est)))\ncat(sprintf(\"Mean diagonal (self-relatedness): %.4f\\n\", mean(diag(A_est))))\ncat(sprintf(\"Mean off-diagonal (pairwise relatedness): %.6f\\n\", \n mean(A_est[upper.tri(A_est)])))\ncat(\"\\nGRM corner (first 5 x 5):\\n\")\nprint(round(A_est[1:5, 1:5], 4))"
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": []
},
"outputs": [],
"source": "# --- 3. ESTIMATE HERITABILITY (REML) ---\n\nfit <- mixed.solve(y = y, K = A_est)\n\nvar_g_est <- fit$Vu\nvar_e_est <- fit$Ve\nh2_est <- var_g_est / (var_g_est + var_e_est)\n\ncat(sprintf(\"Genetic variance (sigma_g^2): %.4f\\n\", var_g_est))\ncat(sprintf(\"Residual variance (sigma_e^2): %.4f\\n\", var_e_est))\ncat(sprintf(\"\\nTrue Heritability: %.2f\\n\", h2_true))\ncat(sprintf(\"Estimated SNP-Heritability: %.2f\\n\", h2_est))"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "# 5. Related Topics\n\n* **LD Score Regression (LDSC):** GREML requires individual-level genotype data (which is private). LDSC allows us to estimate heritability using only Summary Statistics (public) by exploiting LD patterns.\n* **Partitioned Heritability:** We can extend the GREML model to have multiple random effects ($y = X\\beta + g_{coding} + g_{noncoding} + e$). This tells us if genetic variance is enriched in specific functional regions.\n* **BOLT-LMM / SAIGE:** These methods use the same mathematical foundation (Mixed Models) but for a different goal: increasing power to detect specific SNP associations in GWAS, rather than just estimating total variance."
},
{
"cell_type": "markdown",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": "# Results\n\nThe GREML simulation demonstrates that SNP-heritability can be accurately recovered from genotype data alone:\n\n- **True heritability** was set at 0.60\n- **Estimated SNP-heritability** was 0.63, closely matching the true value\n- The GRM successfully captured subtle relatedness structure among unrelated individuals (mean off-diagonal ~ 0), with diagonal values near 1.0 as expected\n- The REML algorithm converged and partitioned total phenotypic variance into genetic and residual components consistent with the generative model\n\nThis confirms the core GCTA insight: even without identifying individual significant SNPs, the aggregate signal across all common variants can explain a substantial fraction of trait heritability."
}
],
"metadata": {
"kernelspec": {
"display_name": "R",
"language": "R",
"name": "ir"
},
"language_info": {
"codemirror_mode": "r",
"file_extension": ".r",
"mimetype": "text/x-r-source",
"name": "R",
"pygments_lexer": "r",
"version": "4.4.3"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
737 changes: 737 additions & 0 deletions LDSC.ipynb

Large diffs are not rendered by default.

14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@ As an example, consider allele-specific expression (ASE) QTL analysis. Total exp

## Overview of Topics

These notes organize into five themes. The first three represent fundamental ways of thinking about genetic data that recur across many applications. The last two address how we adapt our models to specific data types or practical computational constraints. Throughout, the same building blocks, mostly introduced in our ["statgen-primer" notes](https://statfungen.github.io/statgen-primer), appear in different combinations depending on the scientific question.
These notes organize into five themes.

The first three themes represent our understanding of how genetic association relates to biological questions. When studying genetic associations, we fundamentally care about two things: mapping specific effects to variants or contexts (Theme 1) or predicting aggregate outcomes from polygenic architecture (Theme 2). Theme 3 takes both perspectives further by adding causal inference: we can ask mapping questions (which gene's expression causes disease?) or prediction questions (can we predict disease risk through genetically predicted expression?). Causality is necessarily narrower than association—it requires stronger assumptions—but builds on the same conceptual foundations.

The last two address how we adapt our models to specific data types or practical computational constraints. Theme 4 examines how biological data-generating processes inform model design. Unlike simple GWAS phenotypes, molecular data (RNA-seq counts, methylation proportions, splicing ratios) arise from well-understood biological mechanisms that suggest specific distributional choices and model structures. Theme 5 addresses strategic simplification of rigorous generative models for computational tractability.

Throughout, the same building blocks, mostly introduced in our ["statgen-primer" notes](https://statfungen.github.io/statgen-primer), appear in different combinations depending on the scientific question.

### Theme 1: Mapping of shared vs. specific effects

Expand Down Expand Up @@ -55,9 +61,11 @@ It is important to clarify that "causal" here refers to the statistical modeling
|---------------------|---------------|---------------|
| Does gene expression causally affect disease? | TWAS as MR, instrumental variables, predicted expression | PrediXcan, FUSION, MultiXcan, mr.mash, CoMM, cTWAS |
| Does exposure X cause outcome Y? | MR assumptions, horizontal pleiotropy, instrument selection | TwoSampleMR, MR-Egger, MR-PRESSO, MRAID |
| Which among multiple correlated exposures is the driver? | Multivariate MR (MVMR), direct vs. indirect effects, pleiotropy correction | MVMR-Egger, MVMR-cML, GRAPPLE, Cis-MRBEE|
| Can we distinguish causality from pleiotropy? | Horizontal pleiotropy testing, robust MR | PMR-Egger, CAUSE |
| How do we integrate QTL and GWAS evidence for causality? | multi-omics MR | SMR, ... |


### Theme 4: Generative models for molecular phenotypes

This theme examine specific generative modeling to different molecular data types. Unlike GWAS where the phenotype is relatively simple (a quantitative trait or case-control status), molecular phenotypes have complex data generating processes that we understand from biology. Building generative models that respect these structures can improve power and interpretation.
Expand All @@ -74,7 +82,9 @@ This is the Lego analogy in action: we know the biology of RNA-seq count data or

### Theme 5: Scalability and computational approximations

As genetic datasets grow to biobank scale (hundreds of thousands to millions of individuals), statistical methods often become computationally intractable. This theme addresses practical approximations that particularly enable analysis at scale while preserving the core conceptual framework.


Themes 1-4 emphasize building full generative models that capture biological reality. These models are conceptually complete but often computationally intractable at biobank scale. As genetic datasets grow (hundreds of thousands to millions of individuals), statistical methods often become computationally intractable. Theme 5 addresses how we strategically simplify these generative models through approximations that preserve core conceptual framework while enabling computation. The key is understanding what we're dropping and why it still works.

We emphasize tradeoffs to helps practitioners choose appropriate methods between rigorous generative models and scalable approximations.

Expand Down