生物医学网络科学Biomedical Network Science
Example04 / 07

DIAMOnD 疾病模块扩展(连接显著性 + 逐步加入)

所属专题
疾病模块、网络邻近度与药物重定位
下载
Notebook · .py

DIAMOnD(Ghiassian 等 2015):对每个候选节点,计算“在 N 个节点、s0 个种子的网络中,一个度为 k 的节点 至少有 ks 个种子邻居”的超几何尾概率 p,每步把 p 最小的节点并入种子集合,然后重新计算。 这里在合成网络中埋入一个 60 个节点的“真实疾病模块”,只公开其中 30 个作为已知疾病基因(种子), 看 DIAMOnD 前 30 个加入的节点中能找回多少个隐藏的模块成员,并与两个朴素基线比较: “种子邻居数 ks 最多”与“节点度最大”。输出解读:连接显著性同时考虑 ks 与 k, 不会像 ks 排序那样偏爱枢纽,也不会像度排序那样与模块无关。

Output输出图

DIAMOnD 疾病模块扩展(连接显著性 + 逐步加入):输出图 1

Output文字输出

DIAMOnD    前10/20/30 个候选中隐藏模块成员数:[10, 17, 21](共 30 个隐藏成员)
种子邻居数 ks   前10/20/30 个候选中隐藏模块成员数:[7, 13, 13](共 30 个隐藏成员)
度          前10/20/30 个候选中隐藏模块成员数:[0, 0, 0](共 30 个隐藏成员)
DIAMOnD 前 30 个候选的平均度: 7.5 ;ks 排序前 30 个的平均度: 16.0

Code代码

# DIAMOnD(Ghiassian 等 2015):对每个候选节点,计算“在 N 个节点、s0 个种子的网络中,一个度为 k 的节点
# 至少有 ks 个种子邻居”的超几何尾概率 p,每步把 p 最小的节点并入种子集合,然后重新计算。
# 这里在合成网络中埋入一个 60 个节点的“真实疾病模块”,只公开其中 30 个作为已知疾病基因(种子),
# 看 DIAMOnD 前 30 个加入的节点中能找回多少个隐藏的模块成员,并与两个朴素基线比较:
# “种子邻居数 ks 最多”与“节点度最大”。输出解读:连接显著性同时考虑 ks 与 k,
# 不会像 ks 排序那样偏爱枢纽,也不会像度排序那样与模块无关。
import networkx as nx
import numpy as np
from scipy.stats import hypergeom

def planted_module_network(n=2000, m=2, size=60, seed=7):
    """BA 网络 + 在一个随机节点集合内额外加边,形成一个比背景更紧密、但不是孤立团的模块。"""
    rng = np.random.default_rng(seed)
    G = nx.barabasi_albert_graph(n, m, seed=seed)
    module = rng.choice([v for v in G if G.degree(v) <= 6], size=size, replace=False).tolist()
    for _ in range(90):                      # 模块内加 90 条边(平均每个成员多约 3 条)
        u, v = rng.choice(module, size=2, replace=False)
        G.add_edge(int(u), int(v))
    known = sorted(rng.choice(module, size=size // 2, replace=False).tolist())
    hidden = sorted(set(module) - set(known))
    return G, known, hidden

def diamond(G, seeds, n_add, alpha=1):
    """返回按加入顺序排列的 n_add 个节点。alpha>1 时把每个种子计作 alpha 份(原文的种子加权)。"""
    N = G.number_of_nodes()
    S = set(seeds)
    added = []
    for _ in range(n_add):
        s0 = len(seeds) * alpha + (len(S) - len(seeds))          # 加权后的种子数
        Nw = N + (alpha - 1) * len(seeds)
        cand = {v for u in S for v in G[u]} - S
        best, best_p = None, 2.0
        for v in sorted(cand):
            ks_orig = sum(1 for u in G[v] if u in seeds)
            ks = alpha * ks_orig + sum(1 for u in G[v] if u in S and u not in seeds)
            k = G.degree(v) + (alpha - 1) * ks_orig
            p = hypergeom.sf(ks - 1, Nw, s0, k)                    # P(X >= ks)
            if p < best_p:
                best, best_p = v, p
        S.add(best); added.append(best)
    return added

G, known, hidden = planted_module_network()
n_add = 30
d_order = diamond(G, set(known), n_add)
cand = {v for u in known for v in G[u]} - set(known)
ks_order = sorted(cand, key=lambda v: (-sum(1 for u in G[v] if u in known), v))[:n_add]
deg_order = sorted(set(G) - set(known), key=lambda v: (-G.degree(v), v))[:n_add]

H = set(hidden)
for name, order in [("DIAMOnD", d_order), ("种子邻居数 ks", ks_order), ("度", deg_order)]:
    hits = [sum(1 for v in order[:k] if v in H) for k in (10, 20, 30)]
    print(f"{name:10s} 前10/20/30 个候选中隐藏模块成员数:{hits}(共 {len(H)} 个隐藏成员)")
print("DIAMOnD 前 30 个候选的平均度:", np.mean([G.degree(v) for v in d_order]).round(1),
      ";ks 排序前 30 个的平均度:", np.mean([G.degree(v) for v in ks_order]).round(1))

import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 2, figsize=(11, 4.4))
for order, lab, st in [(d_order, "DIAMOnD", "o-"), (ks_order, "most seed neighbours ks", "s--"), (deg_order, "highest degree", "^:")]:
    ax[0].plot(range(1, n_add + 1), np.cumsum([v in H for v in order]), st, ms=3, label=lab)
ax[0].set_xlabel("number of candidates added"); ax[0].set_ylabel("hidden module members recovered")
ax[0].set_title("Recovery of the hidden module"); ax[0].legend()
nodes = set(known) | H | set(d_order)                     # 种子、隐藏成员与 DIAMOnD 候选的诱导子图
Gs = G.subgraph(nodes); pos = nx.spring_layout(Gs, seed=1, k=0.35)
groups = [(known, "C0", "seed (known disease gene)"), ([v for v in d_order if v in H], "C3", "DIAMOnD hit (hidden member)"),
          ([v for v in d_order if v not in H], "C1", "DIAMOnD candidate, not in module"),
          ([v for v in H if v not in d_order], "0.8", "hidden member, missed")]
nx.draw_networkx_edges(Gs, pos, ax=ax[1], edge_color="0.6", alpha=0.4)
for vs, c, lab in groups:
    nx.draw_networkx_nodes(Gs, pos, nodelist=vs, node_color=c, node_size=60, ax=ax[1], label=lab)
ax[1].set_title("Disease module in the network (first 30 DIAMOnD nodes)"); ax[1].axis("off")
ax[1].legend(fontsize=7, loc="lower left", frameon=False)
plt.tight_layout(); plt.show()

Run在浏览器中运行

首次加载 Python 环境约需 20–40 秒;可以修改参数后重新运行。

DIAMOnD 疾病模块扩展(连接显著性 + 逐步加入)