# Core Workflow Steps The six steps in full, with code: data preparation, design specification, DESeq2 fitting, statistical testing, optional LFC shrinkage, and result export. ## Core Workflow Steps ### Step 1: Data Preparation **Input requirements:** - **Count matrix:** Samples × genes DataFrame with non-negative integer read counts - **Metadata:** Samples × variables DataFrame with experimental factors **Common data loading patterns:** ```python # From CSV (typical format: genes × samples, needs transpose) counts_df = pd.read_csv("counts.csv", index_col=0).T metadata = pd.read_csv("metadata.csv", index_col=0) # From TSV counts_df = pd.read_csv("counts.tsv", sep="\t", index_col=0).T # From AnnData import anndata as ad adata = ad.read_h5ad("data.h5ad") counts_df = pd.DataFrame(adata.X, index=adata.obs_names, columns=adata.var_names) metadata = adata.obs ``` **Data filtering:** ```python # Remove low-count genes genes_to_keep = counts_df.columns[counts_df.sum(axis=0) >= 10] counts_df = counts_df[genes_to_keep] # Remove samples with missing metadata samples_to_keep = ~metadata.condition.isna() counts_df = counts_df.loc[samples_to_keep] metadata = metadata.loc[samples_to_keep] ``` ### Step 2: Design Specification The design formula specifies how gene expression is modeled. **Single-factor designs:** ```python design = "~condition" # Simple two-group comparison ``` **Multi-factor designs:** ```python design = "~batch + condition" # Control for batch effects design = "~age + condition" # Include continuous covariate design = "~group + condition + group:condition" # Interaction effects ``` **Design formula guidelines:** - Use formulaic/Wilkinson formula notation (R-style) - Put adjustment variables (e.g., batch) before the main variable of interest - Ensure variables exist as columns in the metadata DataFrame - Use appropriate data types; continuous variables are detected from the formula, and categorical variables can be forced with `C(variable)` or a pandas categorical dtype - Do not use deprecated `design_factors`, `continuous_factors`, or `ref_level` arguments in new workflows ### Step 3: DESeq2 Fitting Initialize the DeseqDataSet and run the complete pipeline: ```python from pydeseq2.dds import DeseqDataSet from pydeseq2.default_inference import DefaultInference inference = DefaultInference(n_cpus=4) dds = DeseqDataSet( counts=counts_df, metadata=metadata, design="~condition", refit_cooks=True, # Refit after removing outliers inference=inference, low_memory=False, ) # Run the complete DESeq2 pipeline dds.deseq2() ``` **What `deseq2()` does:** 1. Computes size factors (normalization) 2. Fits genewise dispersions 3. Fits dispersion trend curve 4. Computes dispersion priors 5. Fits MAP dispersions (shrinkage) 6. Fits log fold changes 7. Calculates Cook's distances (outlier detection) 8. Refits if outliers detected (optional) ### Step 4: Statistical Testing Perform Wald tests to identify differentially expressed genes: ```python from pydeseq2.ds import DeseqStats ds = DeseqStats( dds, contrast=["condition", "treated", "control"], # Test treated vs control alpha=0.05, # Significance threshold cooks_filter=True, # Filter outliers independent_filter=True # Filter low-power tests ) ds.summary() ``` **Contrast specification:** - Format: `[variable, test_level, reference_level]` - Example: `["condition", "treated", "control"]` tests treated vs control - Use a numeric contrast vector for continuous variables or complex coefficients - Default contrasts are no longer supported in PyDESeq2 0.5.x; always provide `contrast` **Result DataFrame columns:** - `baseMean`: Mean normalized count across samples - `log2FoldChange`: Log2 fold change between conditions - `lfcSE`: Standard error of LFC - `stat`: Wald test statistic - `pvalue`: Raw p-value - `padj`: Adjusted p-value (FDR-corrected via Benjamini-Hochberg) ### Step 5: Optional LFC Shrinkage Apply shrinkage to reduce noise in fold change estimates: ```python ds.lfc_shrink(coeff="condition[T.treated]") # Applies apeGLM shrinkage ``` **When to use LFC shrinkage:** - For visualization (volcano plots, heatmaps) - For ranking genes by effect size - When prioritizing genes for follow-up experiments **Important:** Shrinkage affects only the log2FoldChange values, not the statistical test results (p-values remain unchanged). Use shrunk values for visualization but report unshrunken p-values for significance. ### Step 6: Result Export Save results and intermediate objects: ```python # Export results as CSV ds.results_df.to_csv("deseq2_results.csv") # Save significant genes only significant = ds.results_df[ds.results_df.padj < 0.05] significant.to_csv("significant_genes.csv") # Save a portable AnnData object for later inspection dds.to_picklable_anndata().write_h5ad("dds_result.h5ad") ``` Avoid loading pickle files from untrusted sources. For exchange between agents, pipelines, or collaborators, prefer CSV results and `.h5ad` AnnData files.