VIF方差膨胀因子
VIF(方差膨胀因子)
核心问题:多重共线性
当多个自变量之间高度相关时,线性模型会出现多重共线性问题。
直觉理解:假设用 BIO1(年均温)和 BIO10(最暖季均温)同时预测等位基因频率,两者相关性可能高达 0.98。模型无法分辨"到底是哪个变量在起作用",结果是两个变量的回归系数都变得不稳定、标准误极大。
数学定义
对第
其中
| 含义 | VIF值 | |
|---|---|---|
| 0 | 与其他变量完全不相关 | 1 |
| 0.9 | 90% 方差能被其他变量解释 | 10 |
| 0.99 | 高度冗余 | 100 |
阈值选择
| 阈值 | 适用场景 |
|---|---|
| VIF < 3 | 严格,生态学/景观基因组常用 |
| VIF < 5 | 一般推荐 |
| VIF < 10 | 宽松,社会科学常用 |
vifstep 逐步剔除逻辑(R: usdm包)
library(usdm)
vif_result <- vifstep(as.data.frame(env_scaled), th = 10)
逐步迭代流程:
- 计算所有变量的 VIF
- 找到 VIF 最大的变量
- 若 > 阈值,剔除它
- 用剩余变量重新计算 VIF
- 重复,直到所有变量 VIF ≤ 阈值
为什么逐步而非一次性剔除?
剔除一个变量后,其他变量的 VIF 会改变。A 和 B 高度相关,剔除 A 后 B 的 VIF 可能从 12 降到 3,就无需再剔除。
在景观基因组(GEA)中的应用
因变量 vs 自变量
- 自变量(预测变量):气候/环境变量
- 因变量(响应变量):等位基因频率
VIF 筛的是气候变量之间的共线性,与基因组数据无关。
哪些方法需要 VIF 筛选?
| 方法 | 是否需要VIF | 原因 |
|---|---|---|
| RDA | ✅ 必须 | 多变量,所有环境变量同时进入模型 |
| LFMM2 | 建议 | 单变量,但减少冗余检验 |
| BayPass | 建议 | 单变量,但减少冗余检验 |
| GEMMA/单变量GWAS | ❌ 不需要 | 每次一个变量,不存在共线性 |
Sun et al. (iMeta 2026) 用 GEMMA+LFMM+BayPass 单变量方法,直接保留了全部 28 个变量,并非不做 VIF,而是单变量方法本身不需要。
WorldClim BIO 变量的典型共线性结构
温度类(BIO1,2,4,5,6,7,8,9,10,11)→ 内部高度相关
降水类(BIO12,13,14,15,16,17,18,19)→ 内部相关
温度 vs 降水 → 相对独立
VIF 筛选后通常覆盖:年均温、温度季节性、极端温度、年均降水、降水季节性 ← 对应牛的热耐受、季节适应、极端气候、水分代谢。
重要注意
VIF 筛选的是自变量之间的共线性,与因变量无关。筛掉的变量不代表对等位基因频率没影响——只是其信息已被保留变量涵盖,保留反而干扰模型估计。
统计上无法证明因果方向,气候→基因组的方向是基于生物学先验知识,需后续功能验证(eQTL、ATAC-seq等)支持因果推断。
实操代码(本项目:多源环境变量 GEA)
完整流程
library(usdm)
# 读入环境变量总表
env <- read.csv("breeds_master.csv", row.names=1)
# 排除非环境列(品种信息和坐标不参与VIF计算)
non_env <- c("Num","Species","Group","PaperGroup","NewData",
"Location","Longitude_E","Latitude_N")
# 排除Outgroup和n<5的品种(VIF在和GEA相同的品种集合上计算)
exclude_breeds <- rownames(env)[env$PaperGroup == "Outgroup" | env$Num < 5]
env_vars <- env[!rownames(env) %in% exclude_breeds,
!colnames(env) %in% non_env]
cat("品种数:", nrow(env_vars), ",变量数:", ncol(env_vars), "\n")
# VIF逐步过滤(阈值=10)
# ⚠️ 运行时间约1-2分钟(130个变量)
# ⚠️ 警告 "essentially perfect fit" 属正常,不影响结果
vif_result <- vifstep(env_vars, th=10)
cat("保留变量数:", nrow(vif_result@results), "\n")
print(vif_result@results$Variables)
# 提取过滤后的变量
env_filtered <- env_vars[, vif_result@results$Variables]
# 对因NA的沿海品种进行均值填补
# (SOILW、PEVPR坐标落在NCEP海洋格点,无法提取)
for(col in c("PEVPR_dist","SOILW_max","SOILW_dist")){
if(col %in% colnames(env_filtered)){
env_filtered[is.na(env_filtered[,col]), col] <- mean(env_filtered[,col], na.rm=TRUE)
}
}
# 加回坐标(供pRDA或地图可视化使用)
env_for_analysis <- cbind(
env[!rownames(env) %in% exclude_breeds, c("Longitude_E","Latitude_N")],
env_filtered
)
本项目实际结果
| 参数 | 数值 |
|---|---|
| 输入品种数 | 180(排除后127) |
| 输入变量数 | 130(WorldClim BIO×19 + NCEP×64 + CRU×24 + CHELSA×3 + GPCC×4 + PDSI×4 + elevation) |
| VIF过滤后 | 32个 |
| 运行时间 | 约1分钟 |
保留的32个变量:
wc2.1_2.5m_bio_2, wc2.1_2.5m_bio_8, wc2.1_2.5m_bio_9, wc2.1_2.5m_bio_14, wc2.1_2.5m_bio_18, wc2.1_2.5m_bio_19, OLR_dist, PEVPR_dist, PRATE_mean, RHUM_dist, SNOW_mean, SOILW_max, SOILW_dist, SRFP_dist, TCDC_mean, TCDC_dist, UWND_mean, UWND_dist, VWND_mean, VWND_dist, scd, vpd_dist, PRE_dist, PDSI_mean, PDSI_dist, POTTMP_max, WSPD_dist, WET_dist, CLD_max, CLD_dist, FRS_dist, DTR_dist
注意事项
- VIF在GEA相同品种集合上计算:外群和小样本品种的极端环境值会影响变量间共线性结构,应在和分析一致的品种集上做VIF
- 不需要对变量标准化再做VIF:
vifstep内部会处理,直接输入原始值即可 - R读入CSV时列名含特殊字符会被替换:
Longitude (E)会变成Longitude..E.,用grep("ong|ati", colnames(env))确认实际列名 - VIF筛掉的变量不代表不重要:只是其信息已被保留变量涵盖