R语言 正在访问作为apply内的参数传递的变量名

moiiocjp  于 2023-02-10  发布在  其他
关注(0)|答案(3)|浏览(168)

我在另一篇文章中提出了几乎相同的问题,但只要求列名,并收到了一个完美的解决方案,现在我需要的是变量全名
我在函数内部使用“deparse(substitute(x))”来获取作为参数传递的变量名。它工作得很好...但不适用于“lapply”

myfun <- function(x)
{
  return(deparse(substitute(x)))
}

a <- c(1,2,3)
b <- c(4,5,5)
df<-data.frame(a,b)
myfun(df$a)

[1] "df$a"

但是,用“laply "

lapply(df, myfun)
$a
[1] "X[[i]]"

$b
[1] "X[[i]]"

我怎样才能得到'lapply'中的变量名?
谢谢

7lrncoxx

7lrncoxx1#

当您将 Dataframe 传递给lapply时,它将使用双方括号通过 numerical 索引来迭代列,而不是使用$访问器通过 name 索引来迭代列。它等效于使用以下循环:

X <- df
result <- list()

for(i in seq_along(X)) {
  result[[i]] <- myfun(X[[i]])
} 

names(result) <- names(X)

result
#> $a
#> [1] "X[[i]]"
#> 
#> $b
#> [1] "X[[i]]"

因此,简单的deparse(substitute(x))lapply中无法工作。您不是在 * 恢复 * 列名,而是需要从调用堆栈中 * 重构 * 列名。这充满了警告和陷阱,但一个(相对)简单的方法是:

myfun <- function(x) {
  stack <- lapply(sys.calls(), function(x) sapply(as.list(x), deparse))
  
  if(stack[[length(stack)]][1] == 'myfun') {
    return(stack[[length(stack)]][2])
  }
  
  if(stack[[length(stack)]][1] == 'FUN') {
    return(paste0(stack[[length(stack) - 1]][2], '$',
           eval(quote(names(X)[i]), parent.frame())))
  }
  
  deparse(substitute(x))
}

这意味着如果直接调用,您的函数仍然可以工作:

myfun(df$a)
#> [1] "df$a"

但也适用于lapply

lapply(df, myfun)
#> $a
#> [1] "df$a"
#> 
#> $b
#> [1] "df$b"

lapply(iris, myfun)
#> $Sepal.Length
#> [1] "iris$Sepal.Length"
#>
#> $Sepal.Width
#> [1] "iris$Sepal.Width"
#>
#> $Petal.Length
#> [1] "iris$Petal.Length"
#>
#> $Petal.Width
#> [1] "iris$Petal.Width"
#>
#> $Species
#> [1] "iris$Species"

它是专门编写来覆盖直接使用或在lapply中使用的。如果你想扩展它的使用来在其他函数调用中工作,比如Map或各种purrrMap函数,那么这些必须由它们自己的if子句专门覆盖。

x759pob2

x759pob22#

下面是另一个解决方案,它有点冗长,Allen的解决方案要好得多:

myfun <- function(x) {
  pf <- parent.frame()
  x_nm <- deparse(substitute(x))
  frame_n <- sys.nframe()
  
  apply <- FALSE
  while(frame_n > 0) {
    cl <- as.list(sys.call(frame_n))
    if (grepl("apply", cl[[1]])) {
      x_obj <- cl[[2]]
      apply <- TRUE
      break
    }
    frame_n <- frame_n - 1L
  }
  
  if (apply) {
    idx <- parent.frame()$i[]  
    obj <- get(x_obj, envir = pf)
    if (!is.null(names(obj)[idx])) {
      nm_or_idx <- names(obj)[idx]
    } else {
      nm_or_idx <- idx
    }
    x_nm <- paste0(x_obj, '$', nm_or_idx)
  }
  
  return(x_nm)
}

myfun(df$a)
#> [1] "df$a"

lapply(df, myfun)
#> $a
#> [1] "df$a"
#> 
#> $b
#> [1] "df$b"

reprex package(v2.0.1)于2023年2月9日创建

zpjtge22

zpjtge223#

我们可以定义一个字符串'col_name'来获取函数中数据框列的名称。例如,如果col_name是“a”,dfcol_name从数据框中提取“a”列。然后我们可以使用paste()函数来连接字符串'df$'和'col_name':

myfun <- function(col_name) {
  col <- df[[col_name]]
  return(paste("df$", col_name, sep = ""))
}

 lapply(colnames(df), myfun)

输出

[[1]]
[1] "df$a"

[[2]]
[1] "df$b"

如果我们想分配任何数据,我们可以先进行分配,然后运行lapply,例如:

df <- iris
lapply(colnames(df), myfun)

输出

[[1]]
[1] "df$Sepal.Length"

[[2]]
[1] "df$Sepal.Width"

[[3]]
[1] "df$Petal.Length"

[[4]]
[1] "df$Petal.Width"

[[5]]
[1] "df$Species"

希望这能帮上忙。

相关问题