跳转至

740. 环境微生物组生态位建模

一句话概述:用数学模型描述微生物在环境中的"舒适区"——什么温度、pH、营养条件下这种菌最舒服、长得最好,就像给每种微生物画一张"适宜生活条件地图"。


核心知识点速查表

概念白话解释关键工具
生态位(Niche)一个物种在生态系统中的"位置"和"角色"生态学概念
基本生态位没有竞争时物种能生存的全部环境范围理论生态位
实际生态位有竞争后物种实际占据的环境范围实际观察
生态位宽度物种能容忍的环境范围有多广Levins指数
生态位重叠两个物种在环境需求上有多相似Pianka指数
SDM物种分布模型,预测物种在哪些环境出现MaxEnt, RF

一、原理(白话版)

1.1 什么是微生物生态位?

每种微生物都有自己的"舒适区": - Lactobacillus:喜欢酸性环境(pH 4-6),厌氧 - Pseudomonas:喜欢有氧环境,温度范围广 - 嗜热菌:只在>60°C的温泉里才能活

生态位建模就是用数据量化这些偏好: - 这种菌在什么环境变量范围内出现频率最高? - 两种菌的环境偏好重叠多少?(竞争关系预测) - 如果环境改变,哪些菌会受影响?

1.2 在宏基因组中的应用

场景问题方法
肠道不同饮食塑造什么样的微生物组?饮食变量作为环境因子
土壤哪些环境因子决定菌群组成?土壤理化参数+菌群
海洋温度升高对海洋微生物的影响?温度梯度建模
污水处理最佳处理条件是什么?工艺参数优化

二、生态位宽度与重叠计算

2.1 Levins生态位宽度

# ===== 计算Levins生态位宽度 =====
import pandas as pd  # 导入pandas
import numpy as np  # 导入numpy

# 读取物种在不同环境梯度上的丰度
# 假设我们沿pH梯度采样了多个样本
abundance = pd.read_csv("species_by_pH.tsv", sep="\t", index_col=0)
# 行=pH区间(如 4-5, 5-6, 6-7, 7-8, 8-9)
# 列=物种
# 值=相对丰度

def levins_niche_width(abundances):
    """
    Levins生态位宽度指数
    B = 1 / sum(pi^2)
    标准化后: Ba = (B - 1) / (n - 1)
    """
    p = abundances / abundances.sum()  # 转为比例
    p = p[p > 0]  # 去掉0值
    B = 1.0 / np.sum(p ** 2)  # Levins B
    n = len(abundances)  # 环境类别数
    Ba = (B - 1) / (n - 1)  # 标准化到0-1
    return Ba

# 计算每个物种的生态位宽度
niche_widths = {}
for species in abundance.columns:  # 遍历每个物种
    niche_widths[species] = levins_niche_width(abundance[species].values)

niche_df = pd.DataFrame.from_dict(
    niche_widths, orient="index", columns=["Niche_Width"]
).sort_values("Niche_Width", ascending=False)

print("=== 生态位宽度排名 ===")
print(niche_df.head(20))
# Niche_Width接近1 = 广适种(generalist,什么环境都能活)
# Niche_Width接近0 = 特化种(specialist,只能在特定环境活)

2.2 Pianka生态位重叠

# ===== 计算Pianka生态位重叠 =====
def pianka_overlap(sp1_abund, sp2_abund):
    """
    Pianka生态位重叠指数
    O = sum(pi * qi) / sqrt(sum(pi^2) * sum(qi^2))
    值域: 0-1, 越大重叠越多
    """
    p = sp1_abund / sp1_abund.sum()  # 物种1的比例分布
    q = sp2_abund / sp2_abund.sum()  # 物种2的比例分布

    numerator = np.sum(p * q)  # 分子
    denominator = np.sqrt(np.sum(p**2) * np.sum(q**2))  # 分母

    if denominator == 0:
        return 0
    return numerator / denominator

# 计算所有物种对之间的生态位重叠
species_list = abundance.columns.tolist()
n = len(species_list)
overlap_matrix = np.zeros((n, n))  # 初始化重叠矩阵

for i in range(n):
    for j in range(n):
        overlap_matrix[i, j] = pianka_overlap(
            abundance.iloc[:, i].values,
            abundance.iloc[:, j].values
        )

overlap_df = pd.DataFrame(overlap_matrix, 
                           index=species_list, columns=species_list)

# 绘制热图
import matplotlib.pyplot as plt
import seaborn as sns

plt.figure(figsize=(12, 10))
sns.heatmap(overlap_df, cmap="YlOrRd", vmin=0, vmax=1,
            annot=False, square=True)
plt.title("Niche Overlap Between Species (Pianka Index)")
plt.tight_layout()
plt.savefig("niche_overlap_heatmap.png", dpi=300)
plt.show()

三、物种分布模型(SDM)

3.1 用随机森林建模

# ===== 用随机森林预测微生物分布 =====
from sklearn.ensemble import RandomForestRegressor  # 导入随机森林回归
from sklearn.model_selection import cross_val_score  # 导入交叉验证
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# 读取数据
# 环境变量表(行=样本,列=环境因子)
env_data = pd.read_csv("environmental_variables.tsv", sep="\t", index_col=0)
# 列名示例: pH, Temperature, DO, Salinity, TotalN, TotalP

# 物种丰度表
species_data = pd.read_csv("species_abundance.tsv", sep="\t", index_col=0)

# 选择目标物种
target_species = "Lactobacillus"
y = species_data[target_species].values  # 目标变量:物种丰度
X = env_data.values  # 特征:环境变量
feature_names = env_data.columns.tolist()

# 训练随机森林
rf = RandomForestRegressor(
    n_estimators=500,  # 500棵树
    max_depth=10,      # 最大深度10
    random_state=42,
    n_jobs=-1
)

# 交叉验证评估
cv_scores = cross_val_score(rf, X, y, cv=5, scoring="r2")
print(f"R² = {cv_scores.mean():.3f} ± {cv_scores.std():.3f}")

# 拟合最终模型
rf.fit(X, y)

# 特征重要性 = 哪些环境因子最影响这种菌
importances = pd.Series(rf.feature_importances_, index=feature_names)
importances = importances.sort_values(ascending=True)

plt.figure(figsize=(8, 5))
importances.plot(kind="barh", color="#3498db")
plt.xlabel("Feature Importance")
plt.title(f"Environmental Drivers of {target_species}")
plt.tight_layout()
plt.savefig(f"{target_species}_env_drivers.png", dpi=300)
plt.show()

# ===== 偏依赖图:展示环境因子的非线性效应 =====
from sklearn.inspection import PartialDependenceDisplay

fig, axes = plt.subplots(1, 3, figsize=(15, 4))
top3_features = importances.index[-3:].tolist()  # 最重要的3个因子

for i, feature in enumerate(top3_features):
    feat_idx = feature_names.index(feature)
    PartialDependenceDisplay.from_estimator(
        rf, X, [feat_idx], feature_names=feature_names, ax=axes[i]
    )
    axes[i].set_title(f"Effect of {feature}")

plt.suptitle(f"Partial Dependence: {target_species}", fontsize=14)
plt.tight_layout()
plt.savefig(f"{target_species}_partial_dependence.png", dpi=300)
plt.show()

3.2 R语言CCA/RDA分析

# ===== R语言:典范对应分析(CCA)=====
library(vegan)    # 群落生态分析
library(ggplot2)  # 绑图

# 读取数据
species <- read.table("species_abundance.tsv", header=TRUE,
                      row.names=1, sep="\t")
env <- read.table("environmental_variables.tsv", header=TRUE,
                  row.names=1, sep="\t")

# 选择CCA还是RDA?先做DCA看梯度长度
dca <- decorana(species)  # DCA分析
print(dca)
# 如果第一轴梯度长度 > 4 → 用CCA(单峰响应)
# 如果第一轴梯度长度 < 3 → 用RDA(线性响应)

# 运行CCA
cca_result <- cca(species ~ ., data=env)  # 用所有环境变量做CCA
summary(cca_result)

# 检验整体显著性
anova(cca_result, permutations=999)  # 全局检验

# 检验每个环境因子的显著性
anova(cca_result, by="terms", permutations=999)  # 逐项检验

# VIF检查多重共线性
vif.cca(cca_result)  # VIF>10的变量考虑去掉

# 方差分解
# 看各环境因子解释了多少变异
varpart_result <- varpart(species, 
                          ~pH, ~Temperature, ~DO,  # 分三组环境变量
                          data=env)
plot(varpart_result)  # 绘制Venn图

# 绘图
plot(cca_result, display=c("sites", "bp"), type="n")  # 创建空图
points(cca_result, display="sites", pch=19, 
       col=ifelse(env$Group=="Healthy", "blue", "red"))  # 添加样本点
text(cca_result, display="bp", col="darkgreen", cex=0.8)  # 添加环境变量箭头

四、常见报错与解决

报错信息原因解决方案
CCA: all eigenvalues zero物种和环境无相关检查数据是否正确匹配
VIF > 10环境变量间多重共线性去掉高VIF变量或用PCA降维
RF: negative R²模型比随机还差样本量太少或环境变量不相关
DCA: gradient > 10梯度太长使用CCA(非RDA)
Levins B < 0输入了负值确保使用非负的丰度值

五、面试高频问题

Q1: 广适种(Generalist)和特化种(Specialist)在群落中的角色?

A: 广适种(生态位宽)像"万金油",环境变化时数量稳定,提供基础功能。特化种(生态位窄)像"专家",在特定环境中有优势但环境变化时易消失。

Q2: CCA和RDA如何选择?

A: 做DCA看第一轴梯度长度。>4用CCA(物种对环境的响应是单峰形的),<3用RDA(线性响应),3-4都可以试。

Q3: 环境因子和菌群的因果关系怎么建立?

A: 观察性数据只能建立相关性。要建立因果关系需要:①操控实验(改变环境因子看菌群变化);②时间序列(Granger因果检验);③实验验证(培养实验)。


六、速查表

# ===== 生态位分析速查 =====

# 生态位宽度(Levins)
# Ba = (1/sum(pi²) - 1) / (n - 1)
# 接近1=广适种, 接近0=特化种

# 生态位重叠(Pianka)
# O = sum(pi*qi) / sqrt(sum(pi²)*sum(qi²))
# 接近1=完全重叠, 接近0=不重叠

# R语言CCA/RDA选择:
# DCA梯度长度>4 → CCA
# DCA梯度长度<3 → RDA

# Python SDM:
# RandomForest/MaxEnt → 特征重要性 → 偏依赖图

# 关键R包:vegan(CCA, RDA, DCA, PERMANOVA)
# 关键Python包:sklearn(RF, PDPlot)