如何用dplyr计算含虚拟零值的树种平均材积?
森林调查树种材积均值统计问题解决
问题背景
在计算标准森林调查的树木材积汇总统计量时,需按树种分组输出结果。部分稀有树种仅在少数样地出现,未出现的样地中该树种材积实际为0,但使用dplyr::summarize()默认计算的是该树种出现的样地的均值,而非基于所有调查样地的均值。
原始示例代码
# 加载必要包 library(dplyr) library(tidyr) # 设置随机种子保证可复现 set.seed(63) # 创建模拟数据 plots <- c(1:25) species <- c("PSME", "PSME", "PSME", "TSHE", "PSME", "PSME", "PSME", "THPL", "PIMO3", "ACMA3") trees <- data.frame(plot_id = rep(plots,5), species = sample(species, 125, replace=TRUE), vol = rnorm(125, 3250, 30)) %>% arrange(plot_id) # 默认方式计算均值(仅统计树种出现的样地,不符合需求) trees %>% group_by(species) %>% summarize(across(.cols=2, ~mean(.x)))
问题
能否直接通过向dplyr::summarize()传递参数,实现该树种总材积除以调查总样地数来计算均值?
解决方案
临时转换格式方案
通过宽长格式转换补全0值后计算:
# 接上述代码 # 转换为宽格式,按样地聚合各树种材积 trees_sparse <- trees %>% pivot_wider(id_cols = plot_id, names_from=species, values_from = vol, values_fn=sum) # 将NA替换为0(表示该样地无对应树种材积) trees_sparse[is.na(trees_sparse)] <- 0 # 转换回长格式 trees_zeros <- trees_sparse %>% pivot_longer(cols = -1, names_to = "Species", values_to = "Volume") # 计算符合需求的均值 trees_zeros %>% group_by(Species) %>% summarize(across(.cols=2, ~mean(.x)))
更简洁的实现方式
方式1:直接计算总材积/总样地数
无需转换格式,直接在分组后计算总材积除以总样地数:
# 获取调查总样地数 total_plots <- n_distinct(trees$plot_id) # 按树种计算符合需求的均值 trees %>% group_by(species) %>% summarize(mean_vol = sum(vol) / total_plots)
方式2:用complete补全缺失组合
使用tidyr::complete()补全所有样地-树种的组合,缺失的材积设为0,再计算均值:
trees %>% # 补全所有样地与树种的组合,缺失的vol填充为0 complete(plot_id, species, fill = list(vol = 0)) %>% group_by(species) %>% summarize(mean_vol = mean(vol))
内容的提问来源于stack exchange,提问作者Sean McKenzie
相关产品推荐
相关产品推荐

