ora demo
从零实现一个教学版 GSEA并对应项目中的两种基因排序方法。 运行python Learn/gsea_from_scratch.py 依赖numpy、pandas、matplotlib 输出Learn/gsea_output/gsea_results.tsv 和 enrichment_curves.png 说明本代码用于理解算法。正式分析应使用 clusterProfiler、fgsea 或 gseapy 因为成熟工具对置换策略、并列值、NES 和多重检验有更完整的处理。 from pathlib import Path from math import erfc import matplotlib matplotlib.use(Agg) import matplotlib.pyplot as plt import numpy as np import pandas as pd SEED 20260719 def make_demo_data(n_genes500, seedSEED): 构造一份可重复的差异表达表和三个容易观察的基因集。 rng np.random.default_rng(seed) genes np.array([fGene_{i:03d} for i in range(1, n_genes 1)]) log2fc rng.normal(0, 0.7, n_genes) # 人为制造两个生物学信号前 25 个上调随后 25 个下调。 log2fc[:25] 2.5 log2fc[25:50] - 2.5 z log2fc / 0.7 rng.normal(0, 0.5, n_genes) pvalue np.fromiter( (erfc(value / np.sqrt(2)) for value in np.abs(z)), dtypefloat, countn_genes ).clip(1e-300, 1.0) de pd.DataFrame({gene_symbol: genes, log2fc: log2fc, pvalue: pvalue}) gene_sets { UP_PATHWAY: set(genes[:25]), DOWN_PATHWAY: set(genes[25:50]), RANDOM_PATHWAY: set(rng.choice(genes[50:], size25, replaceFalse)), } return de, gene_sets def rank_genes(de, methodsigned_logp): 生成降序排列的基因列表对应 04_enrichment.R 的 rank 计算。 data de.dropna(subset[gene_symbol, log2fc, pvalue]).copy() if method signed_logp: # 上调为正、下调为负P 越小分数绝对值越大。 data[rank_score] np.sign(data[log2fc]) * -np.log10( data[pvalue].clip(lower1e-300) ) elif method log2fc: data[rank_score] data[log2fc] else: raise ValueError(method 必须是 signed_logp 或 log2fc) # 同名基因保留绝对排名分数最大的一条与 R 脚本的处理一致。 data[abs_score] data[rank_score].abs() data data.sort_values(abs_score, ascendingFalse).drop_duplicates(gene_symbol) return data.sort_values(rank_score, ascendingFalse)[[gene_symbol, rank_score]] def enrichment_score(ranked, gene_set, weight1.0): 计算加权运行和及 ESES 是运行和偏离 0 最远的位置。 genes ranked[gene_symbol].to_numpy() scores ranked[rank_score].to_numpy() hits np.isin(genes, list(gene_set)) n_hit, n_total int(hits.sum()), len(genes) if n_hit 0 or n_hit n_total: raise ValueError(基因集与排序列表的交集必须非空且不能覆盖全部基因) hit_weights np.abs(scores[hits]) ** weight # 命中时按排名权重上升未命中时均匀下降。最终运行和应回到 0。 increments np.full(n_total, -1.0 / (n_total - n_hit)) increments[hits] hit_weights / hit_weights.sum() running np.cumsum(increments) max_i, min_i int(np.argmax(running)), int(np.argmin(running)) es running[max_i] if abs(running[max_i]) abs(running[min_i]) else running[min_i] peak_i max_i if es 0 else min_i # 正 ES 的 leading edge 位于峰值之前负 ES 位于谷值之后。 leading genes[: peak_i 1][hits[: peak_i 1]] if es 0 else genes[peak_i:][hits[peak_i:]] return float(es), running, hits, leading def permutation_test(ranked, gene_set, n_perm500, seedSEED): 随机抽取相同大小的基因集得到零分布、名义 P 值和 NES。 rng np.random.default_rng(seed) observed, running, hits, leading enrichment_score(ranked, gene_set) genes ranked[gene_symbol].to_numpy() null_es np.empty(n_perm) for i in range(n_perm): random_set set(rng.choice(genes, sizelen(gene_set), replaceFalse)) null_es[i] enrichment_score(ranked, random_set)[0] same_sign null_es[null_es 0] if observed 0 else -null_es[null_es 0] observed_abs observed if observed 0 else -observed # 加 1 避免有限次置换产生 P0。 pvalue (1 np.sum(same_sign observed_abs)) / (1 len(same_sign)) nes observed / same_sign.mean() return observed, nes, pvalue, running, hits, leading, null_es def benjamini_hochberg(pvalues): 用 BH 方法把多个基因集的名义 P 值校正为 FDR。 pvalues np.asarray(pvalues, dtypefloat) order np.argsort(pvalues) ranked_p pvalues[order] adjusted ranked_p * len(pvalues) / np.arange(1, len(pvalues) 1) adjusted np.minimum.accumulate(adjusted[::-1])[::-1].clip(0, 1) result np.empty_like(adjusted) result[order] adjusted return result def run_demo(rank_methodsigned_logp, n_perm500): de, gene_sets make_demo_data() ranked rank_genes(de, rank_method) details, rows {}, [] for i, (name, genes) in enumerate(gene_sets.items()): result permutation_test(ranked, genes, n_permn_perm, seedSEED i) es, nes, pvalue, running, hits, leading, null_es result details[name] result rows.append({ pathway: name, size: int(hits.sum()), ES: es, NES: nes, pvalue: pvalue, leading_edge: ;.join(leading), }) results pd.DataFrame(rows) results[padj_BH] benjamini_hochberg(results[pvalue]) results results.sort_values(padj_BH) return ranked, results, details def plot_curves(ranked, results, details, output_file): 画出经典 GSEA 图运行富集分数、命中刻线和排名统计量。 fig, axes plt.subplots(3, 1, figsize(10, 8), sharexTrue, gridspec_kw{height_ratios: [3, 0.7, 1.4]}) colors {UP_PATHWAY: #C43D3D, DOWN_PATHWAY: #2878A5, RANDOM_PATHWAY: #666666} for pathway in results[pathway]: es, nes, _, running, hits, *_ details[pathway] axes[0].plot(running, colorcolors[pathway], labelf{pathway} NES{nes:.2f}) axes[1].vlines(np.flatnonzero(hits), 0, 1, colorcolors[pathway], alpha0.65, linewidth0.7) axes[0].axhline(0, colorblack, linewidth0.7) axes[0].set_ylabel(Running ES) axes[0].legend(frameonFalse) axes[1].set_yticks([]) axes[1].set_ylabel(Hits) axes[2].plot(ranked[rank_score].to_numpy(), color#333333, linewidth0.9) axes[2].axhline(0, color#999999, linewidth0.7) axes[2].set_ylabel(Rank score) axes[2].set_xlabel(Genes ordered from high to low rank score) fig.suptitle(GSEA from scratch: enrichment along a ranked gene list) fig.tight_layout() fig.savefig(output_file, dpi160, bbox_inchestight) plt.close(fig) def main(): output_dir Path(__file__).resolve().parent / gsea_output output_dir.mkdir(exist_okTrue) ranked, results, details run_demo(rank_methodsigned_logp, n_perm500) results.to_csv(output_dir / gsea_results.tsv, sep\t, indexFalse) ranked.to_csv(output_dir / ranked_genes.tsv, sep\t, indexFalse) plot_curves(ranked, results, details, output_dir / enrichment_curves.png) print(\nGSEA 的逻辑) print(1. 用 signed_logp 或 log2fc 将所有基因从高到低排序。) print(2. 遇到通路基因时运行和上升否则下降最大偏离值就是 ES。) print(3. 随机基因集产生零分布计算 nominal PES 除以零分布均值为 NES。) print(4. 对多个通路的 P 值做 BH 校正得到教学版 padj_BH。\n) print(results[[pathway, size, ES, NES, pvalue, padj_BH]].to_string(indexFalse)) print(f\n结果已写入{output_dir}) if __name__ __main__: main()

相关新闻

跨网数据交换,安全与效率真的不能兼得吗?

跨网数据交换,安全与效率真的不能兼得吗?

2013年“棱镜门”事件曝光后,各国纷纷加强了网络隔离与数据安全管控。时至今日,政府、军工、金融、医疗等行业均建立了多级隔离网络——办公网、研发网、生产网、测试网各自独立,物理或逻辑上相互隔离。但业务运转偏偏需要数据在这些网络之间…

2026/10/24 9:07:07 阅读更多 →
抖店搬家上货品牌设置无品牌就安全了吗?走过路过别错过

抖店搬家上货品牌设置无品牌就安全了吗?走过路过别错过

抖店搬家上货品牌设置无品牌就安全了吗?走过路过别错过!很多抖店一件代发商家在进行商品搬家上货时,为规避品牌违规,都会统一把商品品牌属性改为无品牌。大部分人默认只要选了无品牌,就能避开侵权、违规扣分风险,高枕无忧批量上架…

2026/10/23 23:25:11 阅读更多 →
U盘管控软件推荐——安得卫士U盘管理系统

U盘管控软件推荐——安得卫士U盘管理系统

一个看似不起眼的U盘,可能成为企业数据安全的“阿喀琉斯之踵”。据统计,超过85%的数据泄露事件始于内部终端非法使用移动存储设备-3。核心技术图纸、财务报表、客户数据,可以被一个未经管控的U盘轻松拷走——防火墙、入侵检测等投入巨资的安全…

2026/10/26 19:50:49 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/10/26 12:00:21 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/10/25 22:36:10 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/10/26 4:52:12 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/10/26 12:00:21 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/10/26 5:00:37 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/10/26 3:16:46 阅读更多 →

日新闻

周新闻

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/26 12:00:19 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/25 13:21:54 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/26 8:34:37 阅读更多 →