使用dplyr对R DataFrame数值列按行计算zscores出现NA的问题求助
问题分析与解决方法
为什么原代码返回NA?
使用rowwise()后,mutate_if(is.numeric, ~scale(.))会对每个数值列的单个单元格执行scale()函数。单个数值的标准差为0,scale()计算时会除以这个0,最终得到NA结果。
可行实现方法
方法1:dplyr原生语法(rowwise + c_across)
利用c_across()获取每行所有数值列的向量,再逐列计算z-score:
library(dplyr) df %>% rowwise() %>% mutate( across(where(is.numeric), ~ (. - mean(c_across(where(is.numeric)))) / sd(c_across(where(is.numeric))) ) ) %>% ungroup() # 取消行分组,避免后续操作受影响
方法2:基础R + apply按行处理
直接提取数值列,用apply按行计算z-score后替换原列:
# 筛选数值型列的位置 num_cols <- sapply(df, is.numeric) # 按行计算z-score并转置(apply返回结果是列优先,需要转置匹配原数据) df[num_cols] <- t(apply(df[num_cols], 1, function(x) (x - mean(x)) / sd(x)))
方法3:tidyr宽转长再转宽
适合需要对行内数据做更多中间处理的场景:
library(dplyr) library(tidyr) df %>% mutate(row_id = row_number()) %>% # 添加行标识 pivot_longer(cols = where(is.numeric), names_to = "col", values_to = "value") %>% group_by(row_id) %>% mutate(z_score = (value - mean(value)) / sd(value)) %>% pivot_wider(names_from = "col", values_from = "z_score") %>% select(-row_id) %>% bind_cols(df %>% select(where(~!is.numeric(.)))) %>% # 合并非数值列 select(all_of(names(df))) # 恢复原数据的列顺序
内容的提问来源于stack exchange,提问作者swathi.upadhya
相关产品推荐
相关产品推荐

