如何在R中按年和DOY计算树木生长阶段的二进制分组均值
问题描述
我有一个数据库,记录了不同年份中不同树木在三个生长阶段(Enlarging、Thickening、Maturing)的细胞存在(1)或缺失(0)情况,数据按年积日(DOY,1月1日为DOY 1)定期采集。可复现的R数据框示例如下:
df <- data.frame("Year" = c(2012, 2012, 2012, 2012, 2012, 2012, 2012, 2012, 2012, 2012, 2013, 2013, 2013, 2013, 2013), "Tree" = c(15, 15, 15, 15, 15, 22, 22, 22, 22, 22, 41, 41, 41, 41, 41), "DOY" = c(65, 97, 125, 177, 214, 65, 97, 125, 177, 214, 61, 99, 118, 166, 221), "Enlarging" = c(0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0), "Thickening" = c(0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0), "Maturing" = c(0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0)) print(df)
输出结果:
Year Tree DOY Enlarging Thickening Maturing 1 2012 15 65 0 0 0 2 2012 15 97 0 0 0 3 2012 15 125 1 1 1 4 2012 15 177 0 1 1 5 2012 15 214 0 0 0 6 2012 22 65 0 0 0 7 2012 22 97 1 0 0 8 2012 22 125 1 1 1 9 2012 22 177 1 1 1 10 2012 22 214 0 0 0 11 2013 41 61 0 0 0 12 2013 41 99 1 0 1 13 2013 41 118 1 1 1 14 2013 41 166 1 1 1 15 2013 41 221 0 0 0
我希望按Year和DOY分组,计算所有树木各生长阶段的二进制均值(即结果为0或1,而非小数形式的算术均值),但尝试以下代码得到的是小数:
df_mean <- df %>% group_by(Year, DOY) %>% summarise(Enlarging_mean = mean(Enlarging), Thickening_mean = mean(Thickening), Mature_mean = mean(Maturing))
也尝试了转换类型,结果仍为小数:
df_mean <- df %>% group_by(Year, DOY) %>% summarise(Enlarging_mean = mean(as.numeric(as.character(Enlarging))), Thickening_mean = mean(as.numeric(as.character(Thickening))), Mature_mean = mean(as.numeric(as.character(Maturing))))
请问如何正确实现需求?
解决方案
你要的“二进制均值”本质是将算术均值转换为0/1的二值结果,常见的两种逻辑如下,可根据实际需求选择:
1. 多数投票(均值≥0.5则取1)
当组内超过一半树木处于该阶段时返回1,否则返回0,直接对均值结果做二值转换即可:
library(dplyr) df_mean <- df %>% group_by(Year, DOY) %>% summarise( Enlarging_mean = as.integer(mean(Enlarging) >= 0.5), Thickening_mean = as.integer(mean(Thickening) >= 0.5), Maturing_mean = as.integer(mean(Maturing) >= 0.5), .groups = "drop" # 取消分组,可选 ) print(df_mean)
输出结果:
# A tibble: 10 × 5 Year DOY Enlarging_mean Thickening_mean Maturing_mean <dbl> <dbl> <int> <int> <int> 1 2012 65 0 0 0 2 2012 97 1 0 0 3 2012 125 1 1 1 4 2012 177 1 1 1 5 2012 214 0 0 0 6 2013 61 0 0 0 7 2013 99 1 0 1 8 2013 118 1 1 1 9 2013 166 1 1 1 10 2013 221 0 0 0
2. 存在性判定(只要有1就返回1)
如果需求是只要组内有至少一棵树木处于该阶段就返回1,用max()替代mean()更高效,因为0/1数据的最大值直接反映是否存在1:
library(dplyr) df_mean <- df %>% group_by(Year, DOY) %>% summarise( Enlarging_mean = max(Enlarging), Thickening_mean = max(Thickening), Maturing_mean = max(Maturing), .groups = "drop" ) print(df_mean)
3. 批量处理多列(高效写法)
如果有更多生长阶段列,用across()批量处理可避免重复代码:
# 多数投票逻辑 df_mean <- df %>% group_by(Year, DOY) %>% summarise( across(c(Enlarging, Thickening, Maturing), ~as.integer(mean(.x) >= 0.5)), .groups = "drop" ) # 存在性判定逻辑 df_mean <- df %>% group_by(Year, DOY) %>% summarise( across(c(Enlarging, Thickening, Maturing), max), .groups = "drop" )
内容的提问来源于stack exchange,提问作者David Almagro
相关产品推荐
相关产品推荐

