在dplyr的mutate语句中使用get函数时出现错误的排查
问题:rowwise()环境下调用get(name)报错的原因与解决
先重现场景:
创建两个对象:
tmp <- list(1,2,4) dafa <- data.frame(thing="Yes", value=4)
用typeof()查看时,列表和数据框都返回list:
typeof(get("tmp")) # list typeof(get("dafa")) # list
需求是生成包含环境中所有对象的数据框,并标记哪些是数据框,于是编写代码:
library(tidyverse) # 获取环境中所有对象并存储为表格 data_items <- map_dfr(ls(), \(itm){ data.frame(name=itm, type=typeof(get(itm)), size=object.size(get(itm)))}) # 调整每行以标记对象是否为数据框 data_items %>% rowwise() %>% mutate(type = ifelse(inherits(get(name), "data.frame"), "data.frame", type))
运行后报错:
Error in get(name) : first argument has length > 1
原因分析
虽然使用了rowwise(),但get()函数并不识别tidyverse的行上下文,它会直接接收整个name列的向量(长度大于1),而get()要求第一个参数必须是单个字符串,因此触发报错。rowwise()主要让聚合类函数(如sum、mean)按行计算,但对get()这类基础函数不起作用。
解决方法
方法一:在rowwise中获取单行的name值
用pick(name)在rowwise上下文里提取当前行的单个name字符串,传给get():
data_items %>% rowwise() %>% mutate(type = ifelse(inherits(get(pick(name)), "data.frame"), "data.frame", type))
或者用cur_data()获取当前行数据后提取name:
data_items %>% rowwise() %>% mutate(type = ifelse(inherits(get(cur_data()$name), "data.frame"), "data.frame", type))
方法二:提前在map阶段完成判断(更高效)
避免后续重复调用get(),直接在第一步遍历对象时就判断是否为数据框:
library(tidyverse) data_items <- map_dfr(ls(), \(itm){ obj <- get(itm) # 只调用一次get,提升效率 data.frame( name = itm, type = if(inherits(obj, "data.frame")) "data.frame" else typeof(obj), size = object.size(obj) ) })
内容的提问来源于stack exchange,提问作者pluke
相关产品推荐
相关产品推荐

