扩增子分析|微生物生态网络稳定性评估之鲁棒性(Robustness)和易损性(Vulnerability)在R中实现
一、引言
周集中老师团队于2021年在Nature climate change发表的文章,阐述了网络稳定性评估的原理算法,并提供了完整的代码。自此对微生物生态网络的评估具有更全面的指标,自此网络稳定性的评估广受大家欢迎。本系列将介绍网络稳定性之鲁棒性和易损性指数的原理,计算方法以及代码,如有疑问欢迎讨论交流。
为了理解增温是否以及如何影响构建的微生物生态网络(MEN)的稳定性,我们使用了多种指标来表征网络及其嵌入成员的稳定性,包括稳健性、易损性、节点和连接的稳定性、节点持久性以及组成稳定性。我们通过消除模拟和经验观察评估了网络及网络内微生物群落的稳定性。这一节集中于基于模拟的方式评估网络稳定性的稳健性(Robustness)和易损性指标。下一节我们将讨论基于经验观测值评估网络稳定性。
二、基础知识之基于模拟的网络稳定性
稳健性(Robustness)
微生物生态网络(MEN)的稳健性定义为在随机或定向移除节点后网络中剩余物种的比例。在随机移除物种的模拟中,随机移除一定比例的节点;在定向移除模拟中,移除了一定数量的模块中心节点。为了测试物种移除对剩余物种的影响,计算了节点 i 的加权平均相互作用强度(wMIS),其公式如下:
式中,bj是物种 j 的相对丰度;
sij 是物种 i 和 j 之间的关联强度,以皮尔森相关系数表示。因此在本研究中,sij = sji。
从MEN中移除选定节点后,如果 wMISi = 0(即所有与物种 i 的链接均被移除)或 wMISi< 0(即物种 i 与其他物种之间的共生协同不足以维持其生存),则节点 i 被视为灭绝/孤立并从网络中移除。该过程持续进行,直到所有物种的 wMIS 均为正数。剩余节点的比例即为网络的稳健性。在随机移除50%的节点或移除5个模块枢纽节点的情况下,测量了网络的稳健性。
图中a,稳健性测量方法是从每个经验MEN 中随机移除 50% 的分类单元后剩余的分类单元比例。b,稳健性测量方法是从每个经验MEN中移除五个模块中心后剩余的分类单元比例。在a和b中,每个误差线对应于 100 次模拟的标准差。变暖(W)和控制(Ctl)之间的显著性差异(双侧t检验)用 *** P < 0.001表示。
易损性(Vulnerability)
每个节点的易损性衡量该节点对全局效率的相对贡献。网络的易损性由网络中节点的最大易损性表示,公式如下:
式中,E 是网络的全局效率;
Ei 是移除节点 i 及其所有链接后的全局效率。
网络图的全局效率计算为所有节点对间效率的平均值:
式中,d(i, j) 表示节点 i 和节点 j 之间最短路径上的边数量。
效率描述了信息在网络中传播的速度。在生态网络中,效率可以提供关于生物或生态事件后果在网络局部或整体传播速度的信息。
图中,网络易损性通过每个网络中的最大节点易损性来衡量。显示了线性回归的调整后R2和P值。
三、示例数据及R代码
本文的示例数据和代码均来自于2021年周集中老师团队的Nature climate change文章,感兴趣的同学可以自行去学习。
3.1 鲁棒性(Robustness)指标
🌟准备数据
准备otu.csv表格,该表格为要计算鲁棒性的网络otu数据表。代码每次计算一个网络的稳健性,因此需要计算几个网络就运行几次代码,每次将输入文件名修改。
🌟完整代码
# 清理工作环境中的所有对象
rm(list = ls())
# 读取 OTU 表格数据
otutab <- read.csv("control_otu.csv", row.names = 1)
otutab[is.na(otutab)] <- 0 # 将 NA 值替换为 0
# 筛选出在至少 12 个样本中存在的 OTU
counts <- rowSums(otutab > 0)
otutab <- otutab[counts >= 12,]
# 转置 OTU 表,计算每种物种的相对丰度
comm <- t(otutab)
sp.ra <- colMeans(comm) / 30000 # 每种物种的相对丰度
#从 OTU 表中计算相关矩阵
cormatrix <- matrix(0, ncol(comm), ncol(comm)) # 初始化相关矩阵
for (i in 1:ncol(comm)) {for (j in i:ncol(comm)) {speciesi <- sapply(1:nrow(comm), function(k) {ifelse(comm[k, i] > 0, comm[k, i], ifelse(comm[k, j] > 0, 0.01, NA))})speciesj <- sapply(1:nrow(comm), function(k) {ifelse(comm[k, j] > 0, comm[k, j], ifelse(comm[k, i] > 0, 0.01, NA))})corij <- cor(log(speciesi)[!is.na(speciesi)], log(speciesj)[!is.na(speciesj)]) # 计算对数变换后的相关性cormatrix[i, j] <- cormatrix[j, i] <- corij # 填充对称矩阵}
}# 设置行名和列名为物种名称
row.names(cormatrix) <- colnames(cormatrix) <- colnames(comm)# 仅保留相关系数大于等于 0.80 的连接
cormatrix2 <- cormatrix * (abs(cormatrix) >= 0.80)
cormatrix2[is.na(cormatrix2)] <- 0 # 将 NA 替换为 0
diag(cormatrix2) <- 0 # 去除自连接# 计算网络连接数量和节点数量
sum(abs(cormatrix2) > 0) / 2 # 连接数
sum(colSums(abs(cormatrix2)) > 0) # 至少有一个连接的节点数# 提取连接网络的矩阵
network.raw <- cormatrix2[colSums(abs(cormatrix2)) > 0, colSums(abs(cormatrix2)) > 0]
sp.ra2 <- sp.ra[colSums(abs(cormatrix2)) > 0]
sum(row.names(network.raw) == names(sp.ra2)) # 检查是否匹配# 鲁棒性模拟函数
# 随机移除部分物种后计算剩余物种比例
rand.remov.once <- function(netRaw, rm.percent, sp.ra, abundance.weighted = TRUE) {id.rm <- sample(1:nrow(netRaw), round(nrow(netRaw) * rm.percent))net.Raw <- netRawnet.Raw[id.rm, ] <- 0; net.Raw[, id.rm] <- 0 # 移除物种if (abundance.weighted) {net.stength <- net.Raw * sp.ra} else {net.stength <- net.Raw}sp.meanInteration <- colMeans(net.stength)id.rm2 <- which(sp.meanInteration <= 0) # 移除无连接的物种remain.percent <- (nrow(netRaw) - length(id.rm2)) / nrow(netRaw)remain.percent
}# 鲁棒性模拟
rmsimu <- function(netRaw, rm.p.list, sp.ra, abundance.weighted = TRUE, nperm = 100) {t(sapply(rm.p.list, function(x) {remains <- sapply(1:nperm, function(i) {rand.remov.once(netRaw = netRaw, rm.percent = x, sp.ra = sp.ra, abundance.weighted = abundance.weighted)})remain.mean <- mean(remains)remain.sd <- sd(remains)remain.se <- sd(remains) / sqrt(nperm)result <- c(remain.mean, remain.sd, remain.se)names(result) <- c("remain.mean", "remain.sd", "remain.se")result}))
}# 加权和非加权模拟
Weighted.simu <- rmsimu(netRaw = network.raw, rm.p.list = seq(0.05, 1, by = 0.05), sp.ra = sp.ra2, abundance.weighted = TRUE, nperm = 100)
Unweighted.simu <- rmsimu(netRaw = network.raw, rm.p.list = seq(0.05, 1, by = 0.05), sp.ra = sp.ra2, abundance.weighted = FALSE, nperm = 100)# 整合结果
dat1 <- data.frame(Proportion.removed = rep(seq(0.05, 1, by = 0.05), 2),rbind(Weighted.simu, Unweighted.simu),weighted = rep(c("weighted", "unweighted"), each = 20),year = rep(2014, 40),treat = rep("Warmed", 40)#根据自己的处理修改treat名称
)# 保存结果到文件
write.csv(dat1, "random_removal_result_Y14_W.csv")# 加载 ggplot2 包
library(ggplot2)# 生成加权网络的结果图
ggplot(dat1[dat1$weighted == "weighted",], aes(x = Proportion.removed, y = remain.mean, group = treat, color = treat)) +geom_line() +geom_pointrange(aes(ymin = remain.mean - remain.sd, ymax = remain.mean + remain.sd), size = 0.2) +scale_color_manual(values = c("blue", "red")) +xlab("Proportion of species removed") +ylab("Proportion of species remained") +theme_light() +facet_wrap(~year, ncol = 3)# 生成非加权网络的结果图
ggplot(dat1[dat1$weighted == "unweighted",], aes(x = Proportion.removed, y = remain.mean, group = treat, color = treat)) +geom_line() +geom_pointrange(aes(ymin = remain.mean - remain.sd, ymax = remain.mean + remain.sd), size = 0.2) +scale_color_manual(values = c("blue", "red")) +xlab("Proportion of species removed") +ylab("Proportion of species remained") +theme_light() +facet_wrap(~year, ncol = 3)
🌟输出结果
如下所示,结果输出名为random_removal_result_Y14_W.csv的表格。
在随机移除50%的节点情况下即Proportion.removed值为0.5时,获得该网络的鲁棒性值0.21278;标准差是0.01966,该值对应于 100 次模拟的标准差。
⚠️ weighted考虑到物种丰度了,ubweighted没有考虑物种丰度。
随后可基于这个结果绘制柱状图或其他图纸。
⚠️移除5个模块中心点的鲁棒性值计算代码我们也放在了示例代码和数据文件中,需要的可以留言获取。
3.2 易损性(vulnerability)指标
🌟准备数据
准备otu.csv表格,该表格为要计算易损性的网络otu数据表。
代码每次计算一个网络的易损性,因此需要计算几个网络就运行几次代码,每次将输入文件名修改。
🌟完整代码
# 清理工作环境中的所有对象
rm(list = ls())# 导入igraph包和自定义的centrality函数
if(!require("igraph")){install.packages("igraph")}
library(igraph)
source("info.centrality.R")#自定义函数#### 获取图结构(Graph)####
# 可以通过以下三种方式获取图结构:
# 1. 读取已有的图
# 2. 从OTU表中构建图
# 3. 从MENAP下载的相关矩阵构建图## 2) 从OTU表中构建图
# 读取OTU表,缺失值替换为0
otutab <- read.csv("treat_otu.csv", row.names = 1)
otutab[is.na(otutab)] <- 0# 筛选至少出现在12个样本中的OTU
counts <- rowSums(otutab > 0)
otutab <- otutab[counts >= 12,]# 转置OTU表,以便进行后续计算
comm <- t(otutab)# 初始化相关矩阵,存储物种间的相关性
cormatrix <- matrix(0, ncol(comm), ncol(comm))# 使用嵌套循环计算OTU之间的相关性
for (i in 1:ncol(comm)) {for (j in i:ncol(comm)) {speciesi <- sapply(1:nrow(comm), function(k) {ifelse(comm[k, i] > 0, comm[k, i], ifelse(comm[k, j] > 0, 0.01, NA))})speciesj <- sapply(1:nrow(comm), function(k) {ifelse(comm[k, j] > 0, comm[k, j], ifelse(comm[k, i] > 0, 0.01, NA))})# 计算物种对数值的相关性corij <- cor(log(speciesi)[!is.na(speciesi)], log(speciesj)[!is.na(speciesj)])cormatrix[i, j] <- cormatrix[j, i] <- corij}
}# 设置相关矩阵的行名和列名
row.names(cormatrix) <- colnames(cormatrix) <- colnames(comm)# 仅保留相关系数大于等于0.80的连接
cormatrix2 <- cormatrix * (abs(cormatrix) >= 0.80)
cormatrix2[is.na(cormatrix2)] <- 0
diag(cormatrix2) <- 0 # 移除自连接
cormatrix2[abs(cormatrix2) > 0] <- 1 # 转换为邻接矩阵# 从邻接矩阵构建无向图g
g <- graph_from_adjacency_matrix(as.matrix(cormatrix2), mode = "undirected", weighted = NULL, diag = FALSE)### 结束图构建部分# 移除孤立节点
iso_node_id <- which(degree(g) == 0)
g2 <- delete.vertices(g, iso_node_id) # 生成不含孤立节点的图g2# 检查节点和连接数
length(V(g2)) # 节点数
length(E(g2)) # 边数# 计算每个节点的易损性
node.vul <- info.centrality.vertex(g2)
max(node.vul) # 输出最大易损性
🌟输出结果
四、参考文献
[1] Yuan, M.M., Guo, X., Wu, L. et al. Climate warming enhances microbial network complexity and stability. Nat. Clim. Chang. 11, 343–348 (2021).
[2] Mengting-Maggie-Yuan/warming-network-complexity-stability
五、相关信息
!!!本文内容由小编总结互联网和文献内容总结整理,如若侵权,联系立即删除!
!!!有需要的小伙伴评论区获取今天的测试代码和实例数据。
📌示例代码中提供了数据和代码,小编已经测试,可直接运行。
以上就是本节所有内容。
相关文章:

扩增子分析|微生物生态网络稳定性评估之鲁棒性(Robustness)和易损性(Vulnerability)在R中实现
一、引言 周集中老师团队于2021年在Nature climate change发表的文章,阐述了网络稳定性评估的原理算法,并提供了完整的代码。自此对微生物生态网络的评估具有更全面的指标,自此网络稳定性的评估广受大家欢迎。本系列将介绍网络稳定性之鲁棒性…...
Client 和 Server 的关系理解
client.py 和 server.py 是基于 MCP(Multi-Component Protocol)协议的客户端-服务端架构,二者的关系如下: 1. 角色分工 server.py:服务端,负责注册和实现各种“工具函数”(如新闻检索、情感分…...

【含文档+PPT+源码】基于微信小程序的社区便民防诈宣传系统设计与实现
项目介绍 本课程演示的是一款基于微信小程序的社区便民防诈宣传系统设计与实现,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含:项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从零开始部署运行本套…...
Kafka的核心组件有哪些?简要说明其作用。 (Producer、Consumer、Broker、Topic、Partition、ZooKeeper)
Kafka 核心组件解析 1. 基础架构图解 ┌─────────┐ ┌─────────┐ ┌─────────┐ │Producer │───▶ │ Broker │ ◀─── │Consumer │ └─────────┘ └─────────┘ └────────…...
Java中对象集合转换的优雅实现【实体属性范围缩小为vo】:ListUtil.convert方法详解
1.业务场景 在开发电商系统时,我们经常需要处理订单信息的展示需求。例如:订单详情页需要显示退款信息列表,而数据库中存储的RefundInfo实体类包含敏感字段,直接返回给前端存在安全风险。此时就需要将RefundInfo对象集合转换为Or…...

【MySQL】存储引擎 - ARCHIVE、BLACKHOLE、MERGE详解
📢博客主页:https://blog.csdn.net/2301_779549673 📢博客仓库:https://gitee.com/JohnKingW/linux_test/tree/master/lesson 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! &…...

代码随想录第41天:图论2(岛屿系列)
一、岛屿数量(Kamacoder 99) 深度优先搜索: # 定义四个方向:右、下、左、上,用于 DFS 中四向遍历 direction [[0, 1], [1, 0], [0, -1], [-1, 0]]def dfs(grid, visited, x, y):"""对一块陆地进行深度…...
Vue插槽(Slots)详解
文章目录 1. 插槽简介1.1 什么是插槽?1.2 为什么需要插槽?1.3 插槽的基本语法 2. 默认插槽2.1 什么是默认插槽?2.2 默认插槽语法2.3 插槽默认内容2.4 默认插槽实例:创建一个卡片组件2.5 Vue 3中的默认插槽2.6 默认插槽的应用场景 …...
中国古代史1
朝代歌 三皇五帝始,尧舜禹相传。 夏商与西周,东周分两段。 春秋和战国,一统秦两汉。 三分魏蜀吴,二晋前后延。 南北朝并立,隋唐五代传。 宋元明清后,皇朝至此完。 原始社会 元谋人,170万年前…...
vue +xlsx+exceljs 导出excel文档
实现功能:分标题行导出数据过多,一个sheet表里表格条数有限制,需要分sheet显示。 步骤1:安装插件包 npm install exceljs npm install xlsx 步骤2:引用包 import XLSX from xlsx; import ExcelJS from exceljs; 步骤3&am…...
nginx之proxy_redirect应用
一、功能说明 proxy_redirect 是 Nginx 反向代理中用于修改后端返回的响应头中 Location 和 Refresh 字段的核心指令,主要解决以下问题:协议/地址透传错误:当后端返回的 Location 包含内部 IP、HTTP 协议或非标准端口时,需修正为…...
在 Flink + Kafka 实时数仓中,如何确保端到端的 Exactly-Once
在 Flink Kafka 构建实时数仓时,确保端到端的 Exactly-Once(精确一次) 需要从 数据消费(Source)、处理(Processing)、写入(Sink) 三个阶段协同设计,结合 Fli…...
Qt 中基于 spdlog 的高效日志管理方案
在开发 Qt 应用程序时,日志记录是一项至关重要的功能,它能帮助我们追踪程序的运行状态、定位错误和分析性能。本文将介绍如何在 Qt 项目中集成 spdlog 库,并封装一个简单易用的日志管理类 QtLogger,实现高效的日志记录和管理。 为什么选择 spdlog? spdlog 是一个快速、头…...

VUE CLI - 使用VUE脚手架创建前端项目工程
前言 前端从这里开始,本文将介绍如何使用VUE脚手架创建前端工程项目 1.预准备(编辑器和管理器) 编辑器:推荐使用Vscode,WebStorm,或者Hbuilder(适合刚开始练手使用),个…...
Linux 学习笔记2
Linux 学习笔记2 一、定时任务调度操作流程注意事项 二、磁盘分区与管理添加新硬盘流程磁盘管理命令 三、进程管理进程操作命令服务管理(Ubuntu) 四、注意事项 一、定时任务调度 操作流程 创建脚本 vim /path/to/script.sh # 编写脚本内容设置可执行权…...
JS DOM操作与事件处理从入门到实践
对于前端开发者来说,让静态的 HTML 页面变得生动、可交互是核心技能之一。实现这一切的关键在于理解和运用文档对象模型 (DOM) 以及 JavaScript 的事件处理机制。本文将带你深入浅出地探索 DOM 操作的奥秘,并掌握JavaScript 事件处理的方方面面。 目录 …...

Java EE初阶——初识多线程
1. 认识线程 线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。 基本概念:一个进程可以包含多个线程,这些线程共享进程的资源,如内存空间、文件描述符等,但每个线程都有自己独…...

如何删除网上下载的资源后面的文字
这是我在爱给网上下载的音效资源,但是发现资源后面跟了一大段无关紧要的文本,但是修改资源名称后还是有。解决办法是打开属性然后删掉资源的标签即可。...
深入解析C++11委托构造函数:消除冗余初始化的利器
一、传统构造函数的痛点 在C11之前,当多个构造函数需要执行相同的初始化逻辑时,开发者往往面临两难选择: class DataProcessor {std::string dataPath;bool verbose;int bufferSize; public:// 基础版本DataProcessor(const std::string&am…...
Python中的事件循环是什么?事件是怎么个事件?循环是怎么个循环
在Python异步编程中,事件循环(Event Loop)是核心机制,它通过单线程实现高效的任务调度和I/O并发处理。本文将从事件的定义、循环的运行逻辑以及具体实现原理三个维度展开分析。 一、事件循环的本质:协程与任务的调度器…...

FPGA图像处理(5)------ 图片水平镜像
利用bram形成双缓冲,如下图配置所示: wr_flag 表明 buffer0写 还是 buffer1写 rd_flag 表明 buffer0读 还是 buffer1读 通过写入逻辑控制(结合wr_finish) 写哪个buffer ;写地址 进而控制ip的写使能 通过状态缓存来跳转buffer的…...
[python] 类
一 介绍 具有相同属性和行为的事物的通称,是一个抽象的概念 三要素: 类名,属性,方法 格式: class 类名: 代码块 class Pepole:name "stitchcool"def getname(self):return self.name 1.1 创建对象(实例化) 格式: 对象名 类名() p1 Pepole()…...

day21python打卡
知识点回顾: LDA线性判别PCA主成分分析t-sne降维 还有一些其他的降维方式,也就是最重要的词向量的加工,我们未来再说 作业: 自由作业:探索下什么时候用到降维?降维的主要应用?或者让ai给你出题&…...
Android开发-Activity启停
在Android应用开发中,Activity是构建用户界面的基本组件之一。它代表了一个单一的、专注的操作,比如查看一张图片或者撰写一封电子邮件。每个Activity都有其生命周期,从创建到销毁,会经历一系列的状态变化。了解并正确管理这些状态…...

ERP学习(一): 用友u8安装
安装: https://www.bilibili.com/video/BV1Pp4y187ot/?spm_id_from333.337.search-card.all.click&vd_sourced514093d85ee628d1f12310b13b1e59b 我个人用vmware16,这位up已经把用友软件和环境(sqlserver2008) 都封城vmx文件了…...

01 | 大模型微调 | 从0学习到实战微调 | AI发展与模型技术介绍
一、导读 作为非AI专业技术开发者(我是小小爬虫开发工程师😋) 本系列文章将围绕《大模型微调》进行学习(也是我个人学习的笔记,所以会持续更新),最后以上手实操模型微调的目的。 (本文如若有…...

海康相机无损压缩
设置无损压缩得到更高的带宽和帧率!...

从机器人到调度平台:超低延迟RTMP|RTSP播放器系统级部署之道
✅ 一、模块定位:跨平台、超低延迟、系统级稳定的音视频直播播放器内核 在无人机、机器人、远程操控手柄等场景中,低延迟的 RTSP/RTMP 播放器并不是“可有可无的体验优化”,而是系统能否闭环、操控是否安全的关键组成。 Windows和安卓播放RT…...

研发效率破局之道阅读总结(5)管理文化
研发效率破局之道阅读总结(5)管理文化 Author: Once Day Date: 2025年5月10日 一位热衷于Linux学习和开发的菜鸟,试图谱写一场冒险之旅,也许终点只是一场白日梦… 漫漫长路,有人对你微笑过嘛… 全系列文章可参考专栏: 程序的艺术_Once-Day…...

单因子实验 方差分析
本文是实验设计与分析(第6版,Montgomery著傅珏生译)第3章单因子实验 方差分析python解决方案。本文尽量避免重复书中的理论,着于提供python解决方案,并与原书的运算结果进行对比。您可以从 下载实验设计与分析(第6版&a…...