如何使用dplyr::mutate基于整个管道数据框的条件创建新列
问题原因
你得到的foo_i_am_getting列全为5的核心原因是:dplyr::mutate默认执行向量化运算,调用myf(.,rn)时会把完整的rn列(长度为5的向量)一次性传入自定义函数,而非逐行传入当前行的rn取值。filter(rn<=value)判断时会将整个rn向量作为阈值,所有行都会满足判断条件,因此返回的行数永远是整个数据框的总行数5。
基础问题解决方案(硬编码列名场景)
在mutate前添加rowwise()函数,让运算逐行执行,每次传入当前行的rn值即可得到预期结果,运算结束后建议用ungroup()取消行分组,避免影响后续操作:
df %>% rowwise() %>% mutate( foo_fixed = myf(., rn), foo_expected = 1:qq ) %>% ungroup()
附加问题解决方案(支持tidyverse风格传列名)
使用tidy evaluation的{{ }}(双大括号语法)捕获用户传入的无引号列名,在函数内直接引用即可,修改后的函数如下:
myf <- function(dataframe, filter_col, value){ result <- dataframe %>% filter({{filter_col}} <= value) %>% nrow() return(result) }
调用时直接传入列名即可,无需添加引号:
df %>% rowwise() %>% mutate( foo_fixed = myf(., rn, rn), # 第一个参数rn指定过滤用的列,第二个参数rn为当前行的阈值 foo_expected = 1:qq ) %>% ungroup()
效率优化提示
如果处理的数据量较大,逐行运算效率偏低,你可以根据实际业务逻辑将自定义函数改写为向量化实现,本简化场景直接用mutate(foo = 1:n())即可得到结果,不过你提到实际计算逻辑更复杂,上述rowwise方案已经可以适配自定义函数的需求。
内容的提问来源于stack exchange,提问作者takmers
相关产品推荐
相关产品推荐

