如何在R语言中计算数据框各列三分位数区间的均值?
三分位数区间均值计算问题解决
问题描述
需要计算数据框中所有变量按city和DOY分组后的三分位数区间均值(示例为第三三分位数区间),但运行现有代码后结果出现大量NaN值。
数据结构示例:
DOY city P BP prune Tmax 100 Bechem 1.283868 0.001742587 1.00 29.07214 123 Bechem 0.000000 0.002593004 0.02 30.42596 345 Bechem 0.000000 0.421595923 0.02 30.03821 100 Bechem 1.283868 0.001742587 1.00 29.07214 123 Bechem 0.000000 0.002593004 0.02 30.42596 345 Bechem 0.000000 0.393785818 0.02 29.03066 100 Bechem 1.283868 0.001742587 1.00 29.07214 123 Bechem 0.000000 0.002593004 0.02 30.42596 345 Bechem 0.000000 0.174428952 0.02 32.00171 100 Bechem 1.283868 0.001742587 1.00 29.07214
现有代码:
Fun_tertile_mean <- function(x,i){ quantile<-quantile(x, c(0:3/3)) datum <- mean(x[x<= quantile[i] & x>quantile[i-1]],na.rm = TRUE) return(datum) } Data_General_2tertile <- Data_General[Data_General$yr_prjctd %in% c(2010,2011,2012,2013,2014,2015),] %>% group_by(city) %>% group_by(DOY) %>% select_if(is.numeric) %>% summarise_all(function(x) Fun_tertile_mean(x,3))
问题原因
- 分组逻辑错误:连续两次调用
group_by()会覆盖前一个分组条件,最终仅按DOY分组,丢失city维度,导致分组数据不符合预期,部分组数据量过少无法计算有效分位数。 - 函数边界处理缺陷:筛选条件
x<= quantile[i] & x>quantile[i-1]会排除等于分位数下限的数值,若分位数与数据值重合,会导致筛选子集为空返回NaN;同时未处理分组数据量<3的情况,此时分位数结果重复,同样会得到空子集。
修正方案
方案1:修复分组逻辑与函数边界
# 修正自定义函数,调整边界并处理数据量不足的情况 Fun_tertile_mean <- function(x, i) { clean_x <- na.omit(x) if (length(clean_x) < 3) { return(NA_real_) } quantiles <- quantile(clean_x, c(0, 1/3, 2/3, 1)) # 按三分位数区间调整筛选逻辑,确保覆盖所有数据 if (i == 1) { subset <- clean_x[clean_x <= quantiles[2]] } else if (i == 3) { subset <- clean_x[clean_x >= quantiles[3]] } else { subset <- clean_x[clean_x > quantiles[2] & clean_x <= quantiles[3]] } mean(subset) } # 同时按city和DOY分组,修正数据筛选逻辑 Data_General_2tertile <- Data_General %>% filter(yr_prjctd %in% 2010:2015) %>% group_by(city, DOY) %>% select_if(is.numeric) %>% summarise_all(~Fun_tertile_mean(., 3), .groups = "drop")
方案2:用ntile简化分箱逻辑(更可靠)
利用dplyr内置的ntile函数直接将数据等分为3组,避免分位数边界问题:
Data_General_2tertile <- Data_General %>% filter(yr_prjctd %in% 2010:2015) %>% group_by(city, DOY) %>% # 为每个数值变量添加三分位数分组标记 mutate(across(where(is.numeric), ~ntile(., 3), .names = "{.col}_tile")) %>% # 筛选第三分位数组的数据 filter(if_all(ends_with("_tile"), ~. == 3)) %>% # 计算各变量均值 summarise(across(where(is.numeric) & !ends_with("_tile"), mean, na.rm = TRUE), .groups = "drop")
说明
- 方案1保留原函数逻辑,修复了核心问题;方案2用内置函数简化流程,出错概率更低。
- 若仍有NaN,需检查分组后的数据量:当分组样本数<3时,无法有效划分三分位数,返回NA属于合理结果,可根据需求过滤这些分组。
内容的提问来源于stack exchange,提问作者Pietro Della Sala
相关产品推荐
相关产品推荐

