deparse(substitute()) with lapply

问题描述 投票:0回答:1

我想用一个小函数与lapply()相结合的方式,给数据框贴标签

我有以下代码。

df1 <- data.frame(c(1,2,3), c(3,4,5))
df2 <- data.frame(c(6,7,8), c(9,10,11))

f.generate.name <- function(x) {
  x$name <- deparse(substitute(x))
  return(x)
  }

my_list <- list(df1, df2) 


# This works fine.
f.generate.name(df1)

# This does not work.
lapply(my_list, f.generate.name)

它产生了以下输出

[[1]]
  c.1..2..3. c.3..4..5.   name
1          1          3 X[[i]]
2          2          4 X[[i]]
3          3          5 X[[i]]

[[2]]
  c.6..7..8. c.9..10..11.   name
1          6            9 X[[i]]
2          7           10 X[[i]]
3          8           11 X[[i]]

我想要的是。

[[1]]
  c.1..2..3. c.3..4..5.   name
1          1          3 df1
2          2          4 df1
3          3          5 df1

[[2]]
  c.6..7..8. c.9..10..11.   name
1          6            9 df2
2          7           10 df2
3          8           11 df2

什么是不使用循环的最佳方法?我如何调整lapply()函数或我创建的函数以达到预期的效果?

r lapply substitution
1个回答
1
投票

基础R

lapply() 不能对多个参数进行迭代。你可以使用 mapply() 或其包装物 Map() 在这种情况下,总是返回一个列表。

Map(f = function(x, y){
    x$name <- y
    x }, 
  my_list, 
  names(my_list))
$df1
  c.1..2..3. c.3..4..5. name
1          1          3  df1
2          2          4  df1
3          3          5  df1

$df2
  c.6..7..8. c.9..10..11. name
1          6            9  df2
2          7           10  df2
3          8           11  df2

Tidyverse

如果你是开放的 purrr 解决方案,您可以使用 imap(). 它使得对象的名称可以很方便的得到。那就不需要写函数了。

my_list <- list(df1 = df1, df2 = df2) 

imap(my_list, ~{
  .x$name <- .y
  .x
  })
$df1
  c.1..2..3. c.3..4..5. name
1          1          3  df1
2          2          4  df1
3          3          5  df1

$df2
  c.6..7..8. c.9..10..11. name
1          6            9  df2
2          7           10  df2
3          8           11  df2

0
投票

真正的问题是这些名字从哪里来? 一个未命名的列表,如 my_list 在问题中已经失去 df1df2 名字,我们可以通过观察它的内部结构来了解。

dput(my_list)  # no df1 or df2 seen
## list(structure(list(c.1..2..3. = c(1, 2, 3), c.3..4..5. = c(3, 
## 4, 5)), class = "data.frame", row.names = c(NA, -3L)), structure(list(
##     c.6..7..8. = c(6, 7, 8), c.9..10..11. = c(9, 10, 11)), class = 
## "data.frame", row.names = c(NA, 
## -3L)))

因此,要么我们需要首先创建一个命名列表,要么提供一个名字的向量。 我们只用基础R来展示这两种情况。

命名列表

首先创建一个数据帧的命名列表,然后使用Map,如图所示。

L <- mget(ls("^df"))  # create named list
Map(data.frame, L, name = names(L))

未命名的列表

另外,如果你有一个未命名的列表,那么我们可以将其映射到该列表和一个名字的向量上。

my_list <- list(df1, df2) # unnamed list as in question
Map(data.frame, my_list, name = c("df1", "df2"))

传递单个数据帧

然而另一种方法是传递单个数据帧而不是列表。 因为我们没有通过创建一个未命名的列表来破坏原始名称,我们仍然可以检索它们。 在R 4.0及以后的版本中 deparse1 可以选择使用 deparse 在代码中。

add_names <- function(...) {
  mc <- match.call()
  Map(data.frame, list(...), names = sapply(mc[-1], deparse))
}

add_names(df1, df2)
© www.soinside.com 2019 - 2024. All rights reserved.