在dplyr中按行计算几何均值实现变量标准化的问题
问题核心
需要对iris数据集的指定列(Sepal.Length、Sepal.Width)做行级标准化:每行的列值除以该行这两个列的几何均值,但原代码错误使用整列数据计算几何均值,导致结果不符预期。
原代码问题分析
原代码中psych::geometric.mean(c(Sepal.Length,Sepal.Width))是将整个Sepal.Length列和Sepal.Width列的所有值合并成一个向量,计算的是全局几何均值,而非每行两个值的几何均值。
正确实现方式
方法1:使用rowwise() + c_across()(推荐的dplyr风格)
通过rowwise()让dplyr按行处理数据,c_across()提取每行指定列的数值组成向量,再计算行级几何均值:
library(dplyr) library(psych) coln1 <- colnames(iris)[1:2] iris_processed <- iris %>% rowwise() %>% # 计算每行指定列的几何均值 mutate(row_geo_mean = geometric.mean(c_across(all_of(coln1)))) %>% # 对指定列做标准化 mutate(across(all_of(coln1), ~ .x / row_geo_mean)) %>% # 取消行分组,避免后续操作受影响 ungroup() # 验证第一行结果:和预期一致 iris_processed[1, coln1] # Sepal.Length Sepal.Width # 1.207107 0.83944
方法2:用自定义几何均值函数
如果不想依赖psych包,替换成你自己的gm_mean函数即可:
gm_mean = function(x, na.rm=TRUE){ exp(sum(log(x[x > 0]), na.rm=na.rm) / length(x)) } iris_processed <- iris %>% rowwise() %>% mutate(row_geo_mean = gm_mean(c_across(all_of(coln1)))) %>% mutate(across(all_of(coln1), ~ .x / row_geo_mean)) %>% ungroup()
方法3:用.by = row_number()实现行级分组(dplyr 1.1.0+支持)
无需显式调用rowwise(),直接按行分组处理:
iris_processed <- iris %>% mutate( across(all_of(coln1), ~ .x / geometric.mean(pick(all_of(coln1)))), .by = row_number() )
关键说明
c_across()/pick()用于在每行中提取指定列的数值,确保几何均值是行级计算- 处理完成后取消行分组(
ungroup())是必要的,避免后续聚合类操作(如summarise)出现非预期的行级结果
内容的提问来源于stack exchange,提问作者G_biof
相关产品推荐
相关产品推荐

