如何使用mutate按行应用函数创建数据框新变量?
用dplyr::mutate实现行级条件判断的解决方案
嗨,我来帮你搞定这个问题!你原来用apply(1, ...)的方式虽然能得到想要的结果,但在tidyverse的工作流里,确实有更贴合mutate的优雅做法,而且代码会更整洁易读。
先说说你之前用mutate失败的原因:mutate默认是按列向量操作的,直接在mutate里用any()会把整列的结果合并成一个单一值,而不是逐行计算——这就是为啥你之前尝试没成功~
下面给你两种可行的tidyverse风格方案,都能完美替代原来的apply写法:
方法1:用rowwise() + c_across()(通用行操作写法)
如果你需要更灵活的行级计算(比如不止判断是否存在某个值,还要做其他复杂行运算),可以用rowwise()把数据框转为行分组模式,再用c_across()提取每行的指定列:
library(tidyverse) n <- 100 z0 <- data.frame(A = sample(c("y","n",NA), n, replace = T, prob = c(.4,.4,.1)), B = sample(c("y","n",NA), n, replace = T, prob = c(.4,.4,.1)), C = sample(c("y","n",NA), n, replace = T, prob = c(.4,.4,.1))) # 生成新变量new z0 <- z0 %>% rowwise() %>% # c_across(A:C) 提取每行的A、B、C列组成向量,any判断是否有"y" mutate(new = any(c_across(A:C) == "y")) %>% ungroup() # 记得取消行分组,避免影响后续操作 summary(z0)
方法2:用if_any()(推荐,更简洁高效)
dplyr专门提供了if_any()函数,用来判断每行是否存在至少一列满足指定条件,完全匹配你当前的需求,而且不需要额外的行分组操作,代码更简洁,性能也更好:
z0 <- z0 %>% # if_any遍历A到C列,检查是否有列等于"y" mutate(new = if_any(A:C, ~ .x == "y")) summary(z0)
验证结果一致性
你可以对比两种方法和原来apply写法的结果,确保完全一致:
# 原来的方法生成的new original_new <- apply(z0, 1, function(x) any("y" == x)) # 新方法生成的new new_new <- z0$new # 检查是否完全相同 all.equal(original_new, new_new)
这个结果会返回TRUE,说明两种方法的输出和你原来的代码完全一致~
内容的提问来源于stack exchange,提问作者Nicolas Molano
相关产品推荐
相关产品推荐

