$npx -y skills add LeonChaoX/qinyan-academic-skills --skill pydeseq2Differential gene expression analysis (Python DESeq2). Identify DE genes from bulk RNA-seq counts, Wald tests, FDR correction, volcano/MA plots, for RNA-seq analysis.
| 1 | # PyDESeq2 |
| 2 | |
| 3 | ## Overview |
| 4 | |
| 5 | PyDESeq2 is a Python implementation of DESeq2 for differential expression analysis with bulk RNA-seq data. Design and execute complete workflows from data loading through result interpretation, including single-factor and multi-factor designs, Wald tests with multiple testing correction, optional apeGLM shrinkage, and integration with pandas and AnnData. |
| 6 | |
| 7 | ## When to Use This Skill |
| 8 | |
| 9 | This skill should be used when: |
| 10 | - Analyzing bulk RNA-seq count data for differential expression |
| 11 | - Comparing gene expression between experimental conditions (e.g., treated vs control) |
| 12 | - Performing multi-factor designs accounting for batch effects or covariates |
| 13 | - Converting R-based DESeq2 workflows to Python |
| 14 | - Integrating differential expression analysis into Python-based pipelines |
| 15 | - Users mention "DESeq2", "differential expression", "RNA-seq analysis", or "PyDESeq2" |
| 16 | |
| 17 | ## Quick Start Workflow |
| 18 | |
| 19 | For users who want to perform a standard differential expression analysis: |
| 20 | |
| 21 | ```python |
| 22 | import pandas as pd |
| 23 | from pydeseq2.dds import DeseqDataSet |
| 24 | from pydeseq2.ds import DeseqStats |
| 25 | |
| 26 | # 1. Load data |
| 27 | counts_df = pd.read_csv("counts.csv", index_col=0).T # Transpose to samples × genes |
| 28 | metadata = pd.read_csv("metadata.csv", index_col=0) |
| 29 | |
| 30 | # 2. Filter low-count genes |
| 31 | genes_to_keep = counts_df.columns[counts_df.sum(axis=0) >= 10] |
| 32 | counts_df = counts_df[genes_to_keep] |
| 33 | |
| 34 | # 3. Initialize and fit DESeq2 |
| 35 | dds = DeseqDataSet( |
| 36 | counts=counts_df, |
| 37 | metadata=metadata, |
| 38 | design="~condition", |
| 39 | refit_cooks=True |
| 40 | ) |
| 41 | dds.deseq2() |
| 42 | |
| 43 | # 4. Perform statistical testing |
| 44 | ds = DeseqStats(dds, contrast=["condition", "treated", "control"]) |
| 45 | ds.summary() |
| 46 | |
| 47 | # 5. Access results |
| 48 | results = ds.results_df |
| 49 | significant = results[results.padj < 0.05] |
| 50 | print(f"Found {len(significant)} significant genes") |
| 51 | ``` |
| 52 | |
| 53 | ## Core Workflow Steps |
| 54 | |
| 55 | ### Step 1: Data Preparation |
| 56 | |
| 57 | **Input requirements:** |
| 58 | - **Count matrix:** Samples × genes DataFrame with non-negative integer read counts |
| 59 | - **Metadata:** Samples × variables DataFrame with experimental factors |
| 60 | |
| 61 | **Common data loading patterns:** |
| 62 | |
| 63 | ```python |
| 64 | # From CSV (typical format: genes × samples, needs transpose) |
| 65 | counts_df = pd.read_csv("counts.csv", index_col=0).T |
| 66 | metadata = pd.read_csv("metadata.csv", index_col=0) |
| 67 | |
| 68 | # From TSV |
| 69 | counts_df = pd.read_csv("counts.tsv", sep="\t", index_col=0).T |
| 70 | |
| 71 | # From AnnData |
| 72 | import anndata as ad |
| 73 | adata = ad.read_h5ad("data.h5ad") |
| 74 | counts_df = pd.DataFrame(adata.X, index=adata.obs_names, columns=adata.var_names) |
| 75 | metadata = adata.obs |
| 76 | ``` |
| 77 | |
| 78 | **Data filtering:** |
| 79 | |
| 80 | ```python |
| 81 | # Remove low-count genes |
| 82 | genes_to_keep = counts_df.columns[counts_df.sum(axis=0) >= 10] |
| 83 | counts_df = counts_df[genes_to_keep] |
| 84 | |
| 85 | # Remove samples with missing metadata |
| 86 | samples_to_keep = ~metadata.condition.isna() |
| 87 | counts_df = counts_df.loc[samples_to_keep] |
| 88 | metadata = metadata.loc[samples_to_keep] |
| 89 | ``` |
| 90 | |
| 91 | ### Step 2: Design Specification |
| 92 | |
| 93 | The design formula specifies how gene expression is modeled. |
| 94 | |
| 95 | **Single-factor designs:** |
| 96 | ```python |
| 97 | design = "~condition" # Simple two-group comparison |
| 98 | ``` |
| 99 | |
| 100 | **Multi-factor designs:** |
| 101 | ```python |
| 102 | design = "~batch + condition" # Control for batch effects |
| 103 | design = "~age + condition" # Include continuous covariate |
| 104 | design = "~group + condition + group:condition" # Interaction effects |
| 105 | ``` |
| 106 | |
| 107 | **Design formula guidelines:** |
| 108 | - Use Wilkinson formula notation (R-style) |
| 109 | - Put adjustment variables (e.g., batch) before the main variable of interest |
| 110 | - Ensure variables exist as columns in the metadata DataFrame |
| 111 | - Use appropriate data types (categorical for discrete variables) |
| 112 | |
| 113 | ### Step 3: DESeq2 Fitting |
| 114 | |
| 115 | Initialize the DeseqDataSet and run the complete pipeline: |
| 116 | |
| 117 | ```python |
| 118 | from pydeseq2.dds import DeseqDataSet |
| 119 | |
| 120 | dds = DeseqDataSet( |
| 121 | counts=counts_df, |
| 122 | metadata=metadata, |
| 123 | design="~condition", |
| 124 | refit_cooks=True, # Refit after removing outliers |
| 125 | n_cpus=1 # Parallel processing (adjust as needed) |
| 126 | ) |
| 127 | |
| 128 | # Run the complete DESeq2 pipeline |
| 129 | dds.deseq2() |
| 130 | ``` |
| 131 | |
| 132 | **What `deseq2()` does:** |
| 133 | 1. Computes size factors (normalization) |
| 134 | 2. Fits genewise dispersions |
| 135 | 3. Fits dispersion trend curve |
| 136 | 4. Computes dispersion priors |
| 137 | 5. Fits MAP dispersions (shrinkage) |
| 138 | 6. Fits log fold changes |
| 139 | 7. Calculates Cook's distances (outlier detection) |
| 140 | 8. Refits if outliers detected (optional) |
| 141 | |
| 142 | ### Step 4: Statistical Testing |
| 143 | |
| 144 | Perform Wald tests to identify differentially expressed genes: |
| 145 | |
| 146 | ```python |
| 147 | from pydeseq2.ds import DeseqStats |
| 148 | |
| 149 | ds = DeseqStats( |
| 150 | dds, |
| 151 | contrast=["condition", "treated", "control"], # Test treated vs control |
| 152 | alpha=0.05, # Significance threshold |
| 153 | cooks_filter=True, # Filter outliers |
| 154 | independent_filter=True # Filter low-power tests |
| 155 | ) |
| 156 | |
| 157 | ds.summary() |
| 158 | ``` |
| 159 | |
| 160 | **Contrast specification:** |
| 161 | - Format: `[variable, test_level, referenc |