我想拥有一个可以使用从dplyr导出的管道运算符的函数。我没有使用magrittr。
df %>% my_function
如何获得df名称?如果我尝试
my_function <- function(tbl){print(deparse(substitute(tbl)))}
返回
[1] "."
而我想拥有[1]“ df”
有任何建议吗?
谢谢你,尼古拉
这是一种骇人听闻的方法,我敢肯定,在很多情况下,这种方法会被打破:
library(data.table) # for the address function
# or parse .Internal(inspect if you feel masochistic
fn = function(tbl) {
objs = ls(parent.env(environment()))
objs[sapply(objs,
function(x) address(get(x, env = parent.env(environment()))) == address(tbl))]
}
df = data.frame(a = 1:10)
df %>% fn
#[1] "df"
注释中的JBGruber links to大部分解决了SO的答案。它通过在执行环境中向上移动直到找到某个变量,然后从该环境返回lhs
来工作。唯一缺少的是该函数必须同时输出原始数据帧的名称和操作数据 –我从OP的注释之一中收集了后者的要求。为此,我们只需要输出包含这些内容的列表,就可以通过修改MrFlick的答案来做到这一点:
get_orig_name <- function(df){
i <- 1
while(!("chain_parts" %in% ls(envir=parent.frame(i))) && i < sys.nframe()) {
i <- i+1
}
list(name = deparse(parent.frame(i)$lhs), output = df)
}
现在我们可以将get_orig_name
运行到任何管道的末尾,以获取操作数据和列表中原始数据帧的名称。我们使用$
进行访问:
mtcars %>% summarize_all(mean) %>% get_orig_name
#### OUTPUT ####
$name
[1] "mtcars"
$output
mpg cyl disp hp drat wt qsec vs am gear carb
1 20.09062 6.1875 230.7219 146.6875 3.596563 3.21725 17.84875 0.4375 0.40625 3.6875 2.8125
我还应该提到,尽管我认为该策略的细节很有趣,但我也认为它不必要地复杂。听起来OP的目标是处理数据,然后将其写入与原始未经处理的数据帧同名的文件中,这可以使用更直接的方法轻松完成。例如,如果我们要处理多个数据帧,则可以执行以下操作:
df_list <- list(mtcars = mtcars, iris = iris)
for(name in names(df_list)){
df_list[[name]] %>%
group_by_if(is.factor) %>%
summarise_all(mean) %>%
write.csv(paste0(name, ".csv"))
}
受到gersht提到的Link的启发。
您可以返回5代以获得名称,答案如下:
library(dplyr)
a <- 1
df1 <- data.frame(a = 1:10)
df2 <- data.frame(a = 1:10)
a %>% {parent.frame(5)$lhs}
df1 %>% {parent.frame(5)$lhs}
df2 %>% {parent.frame(5)$lhs}
我相信,如果不向您的my_function
添加额外的参数,这是不可能的。当使用dplyr
链接功能时,它会自动将df
转换为tbl_df
对象,因此在"."
范围内使用了新名称dplyr
以简化管道。
以下是dplyr的一个非常怪诞的方法,它只是添加了一个附加参数来返回原始data.frame
的名称>
my_function <- function(tbl, orig.df){print(deparse(substitute(orig.df)))} df %>% my_function(df) [1] "df"
注意,不能将
df
与原始函数一起传递,因为tbl_df
对象会自动传递给所有后续函数。