ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

R语言FD包计算功能多样性:从数据整理到dbFD实操

R语言FD包计算功能多样性:从数据整理到dbFD实操 做群落数据分析的同学应该都有这种体会R语言里真正难的不是模型和指数公式而是数据格式整理。功能多样性指数更是这样——dbFD()这个函数本身跑起来不过几秒钟但前面的数据表到底该长什么样、行名列名怎么对齐、分类性状怎么处理能让人折腾一整晚。这篇文章把我项目里反复用到的一套功能多样性计算流程完整过一遍从数据格式整理到FD包实操再到各种warning的真实含义希望对正在跟功能多样性指数较劲的朋友有点帮助。1. 功能多样性指数是什么先搞清楚你要算什么1.1 五个核心指数各自回答不同生态学问题功能多样性不是某一个指标而是一组从不同侧面描述群落功能特征的指数。我最常用也最推荐新手优先掌握的是这五个它们都在FD::dbFD()里一次性输出指数中文常用译名核心生态学含义FRic功能丰富度群落占据了多少功能空间反映群落能利用的资源和功能潜力FEve功能均匀度物种在功能空间里分布得是否均匀和群落的资源利用效率有关FDiv功能发散度物种是聚集在功能空间中心附近还是向边缘发散反映生态位分化程度FDis功能离散度各物种到功能空间重心的平均距离用丰度加权衡量群落的整体生态位广度RaoQ二次熵随机抽取两个个体时它们的平均功能差异生态位差异越大值越高你可以把群落想象成一群人站在一个抽象空间里这个空间由性状轴株高、叶面积等定义。FRic是这群人占据的总面积FEve是大家站得是否均匀FDiv是有没有人站到边缘去FDis和RaoQ则衡量人与人之间的平均差异有多大。不同研究问题侧重的指数也不同想知道生境过滤有多强重点看FRic和FDiv想评估生态位分化FDis和RaoQ更直接涉及资源分配完整性时FEve是关键。1.2 为什么不能只用Shannon多样性代替物种多样性指数Shannon、Simpson只考虑物种数目和相对多度不考虑物种之间功能的相似或差异。一个20个物种全是禾草的群落和一个20个物种包含乔木、灌木、草本、藤本的群落Shannon指数可能差不多但功能多样性差异巨大对生态系统过程的影响也完全不同。所以现在的群落生态研究里功能多样性通常和物种多样性搭配使用解释互补性、生态位分化这些机制性问题时说服力更强。2. 数据格式整理90%的报错都发生在这里2.1 群落数据表必须是“宽格式”功能多样性计算要求的群落数据是典型的宽格式行是样方列是物种里面是相对丰度或绝对多度。举个例子样方sp1sp2sp3sp4site15302site20160site32024在R里读进来以后关键是行名必须是样方编号列名必须是物种名而且单元格不能有字符型内容。很多原始表第一列叫“样方号”、“site_id”这不是真正的行名必须先转一下library(tibble) comm - comm_raw %% column_to_rownames(样方号)转完之后记得看一眼rownames(comm)和colnames(comm)确认没有变成“...1”这种自动生成的列名。这个问题在Excel或CSV读入时特别常见因为空列名会被R默认成X、X.1等。2.2 性状数据表必须是“物种×性状”性状数据是另一张表行是物种列是性状。常见性状包括株高、比叶面积、叶片干物质含量、种子质量、生活型等。第一个核心要求是性状表的行名必须和群落表的列名完全一致。很多新手在这里把表建反了性状表变成一行一个物种、一列一个样方dbFD()一跑就各种报错。第二个核心要求是进入计算的性状列得是数值型。像生活型这种分类变量直接放到dbFD()里会报错后面会讲怎么处理。你可以用str()检查数据结构str(traits)如果发现某个数值性状被R识别成了chr或Factor需要先转一下traits$height - as.numeric(traits$height)2.3 从长格式到宽格式用pivot系列函数解决实际野外采样数据通常不是宽格式而是长格式每条记录一行包含样方、物种、多度三个核心字段。比如这样样方物种多度site1sp15site1sp23site2sp36这种情况先要用tidyr::pivot_wider()转成宽格式library(tidyr) library(dplyr) comm_wide - comm_long %% pivot_wider( names_from 物种, values_from 多度, values_fill 0 ) %% column_to_rownames(样方)values_fill 0这一步不能省否则该物种没有出现的样方会得到NA后面dbFD()可能直接给你报错。转出来之后检查一下是否有NA残留。还有一种更原始的数据形态每个物种做了多个个体重复测量记录里是一行一个个体的性状数值需要先聚合成物种平均值再进入功能多样性分析trait_means - raw_trait_data %% group_by(species) %% summarise( height mean(height, na.rm TRUE), SLA mean(SLA, na.rm TRUE), seed_mass mean(seed_mass, na.rm TRUE) ) %% column_to_rownames(species)3. 实操用FD包把指数一次算出来3.1 为什么选FD包R里能算功能多样性的包不少FD这个包是生态学里非常经典的选择原因很直接一个函数dbFD()同时输出五个核心指数不用你自己一个个写循环支持丰度加权和存在/缺失两种模式还能借助gowdis()处理分类性状和数值性状混合的情况。vegan主要是物种多样性老牌包功能多样性不是它的强项mFD和TPD虽然更新但生态圈里现在引用和参考最多的还是FD包的思路。安装和加载很简单install.packages(FD) library(FD)3.2 标准流程从两张表到五个指数我构造一个八物种、六个样方的小例子来演示。先准备全数值性状表traits_num - data.frame( row.names c(sp1,sp2,sp3,sp4,sp5,sp6,sp7,sp8), height c(23, 45, 18, 67, 34, 12, 56, 40), SLA c(18.5, 12.2, 25.7, 9.8, 16.1, 30.2, 11.3, 14.8), seed_mass c(0.5, 2.1, 0.2, 3.4, 0.8, 0.1, 1.9, 1.2) )再准备群落数据表行是样方列是物种值为多度comm - data.frame( row.names c(site1,site2,site3,site4,site5,site6), sp1 c(5, 0, 0, 2, 0, 1), sp2 c(3, 1, 0, 0, 4, 0), sp3 c(0, 6, 2, 0, 1, 3), sp4 c(0, 0, 4, 1, 0, 2), sp5 c(2, 3, 0, 5, 0, 0), sp6 c(0, 1, 3, 0, 2, 4), sp7 c(1, 0, 0, 3, 3, 0), sp8 c(0, 2, 1, 0, 1, 5) )建议在计算前加一个物种名匹配检查stopifnot(all(colnames(comm) %in% rownames(traits_num)))然后就是核心的一行res - dbFD(x traits_num, a comm, w.abun TRUE, stand.x TRUE) res$FRic res$FEve res$FDiv res$FDis res$RaoQ说下这里几个参数的逻辑x是性状表a是群落表w.abun TRUE表示用多度加权因为群落里常见种和稀有种对功能多样性的贡献完全不同stand.x TRUE表示对性状做标准化默认就是打开非常重要因为株高和种子质量量纲差异太大如果不标准化权重会被数值大的性状主导。3.3 含分类性状时怎么办Gower距离法实际研究里性状不可能全是数值比如生活型乔木、灌木、草本、光合途径C3、C4就是分类变量。直接放进数值性状表里dbFD()会报错。我的做法是计算Gower距离traits_all - data.frame( row.names c(sp1,sp2,sp3,sp4,sp5,sp6,sp7,sp8), height c(23, 45, 18, 67, 34, 12, 56, 40), SLA c(18.5, 12.2, 25.7, 9.8, 16.1, 30.2, 11.3, 14.8), seed_mass c(0.5, 2.1, 0.2, 3.4, 0.8, 0.1, 1.9, 1.2), life_form factor(c(herb,shrub,herb,tree,shrub,herb,tree,shrub)) ) gdist - FD::gowdis(traits_all) res2 - dbFD(x gdist, a comm, w.abun TRUE)gowdis()是FD包自带的距离函数能同时处理数值型、二元型、有序分类和无序分类混合的情况不需要手动把生活型转成0/1哑变量。不过需要注意当x传进来的是距离矩阵而不是原始性状时stand.x会被忽略而且FRic这种依赖原始坐标空间凸包的指数在部分情况下会失效所以这种模式我主要看FDis、RaoQ和FEve。3.4 结果怎么读res是一个列表每个元素对应一个指数向量长度等于样方数。我习惯把它们拼成一张表再看fd_out - data.frame( site rownames(comm), FRic res$FRic, FEve res$FEve, FDiv res$FDiv, FDis res$FDis, RaoQ res$RaoQ ) print(fd_out)读结果时注意FEve理论上在0到1之间FRic的绝对数值取决于性状标准化后的尺度不同研究之间不能直接比关键是样方之间的相对高低FDis和RaoQ都与性状实际尺度有关所以也在同一套数据内部做比较。4. 实战踩坑物种名匹配、缺失值与warning解读4.1 物种名对不上这是最常见的错dbFD()在实际项目中返回的第一个报错十次有八次是物种名不匹配。比如群落表用“sp 1”带空格性状表用“sp1”或者一个表是“Betula_platyphylla”另一个是“Betula platyphylla”。我踩过一次很大的坑是整个数据分析做到一半才发现有一半物种名对不上所有输出都是基于被静默删掉物种后的矩阵。建议提前做一次系统检查species_only_in_comm - setdiff(colnames(comm), rownames(traits_num)) species_only_in_traits - setdiff(rownames(traits_num), colnames(comm))如果species_only_in_comm里有内容说明有些物种出现在群落表里但没有对应性状dbFD()会把这些物种忽略或直接报错这时要么补测性状要么在群落表里删掉这些列。另外清理数据时统一用trimws()去掉首尾空格再用make.names()规范列名能省掉很多麻烦。4.2 性状缺失值先补全再进模型植物性状数据几乎不可能完整总有几个物种的种子质量没测到。dbFD()遇到NA会直接拒绝计算。常用的处理逻辑是如果缺失少用该性状的均值或中位数填充如果缺失有一定结构比如某个科的物种都缺同一个性状建议先检查是不是测量遗漏别盲目插补。实在没办法也可以用mice包做多重插补。但填充这件事会影响结果所以论文里一定要写明填补方法和比例。群落表里还有一类隐藏的“缺失”某个样方全是0也就是空样方。这种样方在所有指数里都算不出有意义的数字最好在预处理阶段就删掉keep_site - rowSums(comm) 0 comm - comm[keep_site, ]4.3 那些warning到底是什么意思dbFD()跑完弹出一堆warning很多人心里发慌。我整理几个最常见的warning信息含义处理建议Some species in a were not found in x群落表里有物种没有对应性状检查错别字核对命名规则Species in x not found in a性状表里有物种不在群落中不影响计算但确认是否需要保留FRic not calculated / NA性状数量太少凸包体积计算不稳定检查性状数量考虑用FDis、RaoQ替代stand.x is ignored传入的是距离矩阵而非原始性状符合预期不用处理其中warning看起来不报错但结果里会出现NA很容易被忽略。我的习惯是每次跑到结果后先数一下NA数量如果样方数量不多直接打出来看看是哪个样方出了问题。4.4 丰度要不要转换取决于你的研究问题计算功能多样性时a矩阵可以直接放绝对多度也可以放0/1存在-缺失数据甚至可以放相对丰度。不同选择背后是不同生态学假设如果你关心群落的功能组成和占优种效应用丰度加权如果你只关心物种在功能空间上的占据范围存在/缺失就够了。w.abun TRUE/FALSE就是切换这个逻辑的开关。我个人做环境梯度调查时通常保留丰度做保护区评价或快速生物多样性评估时有时改为0/1因为调查数据本身就有采样强度差异。5. 结果输出和批量处理几个提效小习惯5.1 一次性导出五个指数每次跑完都在R里看没法交差也没法和同事交流。我习惯直接把结果拼成表导出write.csv(fd_out, fd_results.csv, row.names FALSE)这个表后面可以直接合并到环境变量、物种多样性指数里作为后续GLM、RDA、方差分解分析的输入。5.2 批量计算多个数据集如果你的数据分年份或分区域存放最好写一个小函数包起来calc_fd - function(traits, comm) { dbFD(x traits, a comm, w.abun TRUE, stand.x TRUE) } results_list - lapply(my_sites, function(site) { calc_fd(traits traits_list[[site]], comm comm_list[[site]]) })需要注意lapply跑出来的每个对象都是dbFD的列表你最后还是得在每个列表里把$FRic、$FEve等抽出来合并。数据量大时FD包运行速度会下降但常规样方数个人感觉还好。5.3 快速可视化一眼看到差异导出之前先用ggplot2画个简单的分组柱状图或箱线图能快速发现异常样方library(ggplot2) library(tidyr) fd_long - fd_out %% pivot_longer(-site, names_to index, values_to value) ggplot(fd_long, aes(x site, y value)) geom_col() facet_wrap(~ index, scales free_y) theme_bw()如果某个样方在FRic上出现断崖式偏低先别急着解释生态学机制回头检查群落表是不是存在全0列或多度录入错误。可视化在这时候起到的是数据质控作用。5.4 导出前的最终检查清单我每次出结果之前会按下面几步过一遍群落表的列名和性状表的行名完全匹配没有多余物种和缺失物种性状表里没有NA分类变量已经通过Gower距离或其他方式处理空样方已删除群落表每一行和每一列的多度和不为零dbFD()的warning都看了一遍确认不影响本次研究的核心指数输出表的行数等于样方数没有因为匹配问题悄悄丢样方最后分享一点个人体会功能多样性分析这个事统计模型反而不是瓶颈真正的功夫全在数据整理和细心校对。我现在拿到任何一批新数据都先花半小时做两张表的结构检查和物种名清洗后面跑dbFD()几乎都是一次通过。这套流程我用了很多年希望能帮你少走点弯路。
返回列表