【问题标题】:Use object names within a list in lapply/ldply在 lapply/ldply 的列表中使用对象名称
【发布时间】:2013-02-19 07:16:55
【问题描述】:

在之前尝试回答a question 时,我遇到了一个看起来应该很简单的问题,但我想不通。

如果我有一个数据框列表:

df1 <- data.frame(a=1:3, x=rnorm(3))
df2 <- data.frame(a=1:3, x=rnorm(3))
df3 <- data.frame(a=1:3, x=rnorm(3))

df.list <- list(df1, df2, df3)

我想rbind一起,我可以这样做:

df.all <- ldply(df.list, rbind)

但是,我想要另一列来标识每行来自哪个data.frame。我希望能够使用deparse(substitute(x)) 方法(here 和其他地方)来获取相关data.frame 的名称并添加一列。这就是我的处理方式:

fun <- function(x) {
  name <- deparse(substitute(x))
  x$id <- name
  return(x)
}
df.all <- ldply(df.list, fun)

返回

  a          x      id
1 1  1.1138062 X[[1L]]
2 2 -0.5742069 X[[1L]]
3 3  0.7546323 X[[1L]]
4 1  1.8358605 X[[2L]]
5 2  0.9107199 X[[2L]]
6 3  0.8313439 X[[2L]]
7 1  0.5827148 X[[3L]]
8 2 -0.9896495 X[[3L]]
9 3 -0.9451503 X[[3L]]

所以显然列表中的每个元素都不包含我认为的名称。谁能建议一种方法来获得我的期望(如下所示)?

  a          x  id
1 1  1.1138062 df1
2 2 -0.5742069 df1
3 3  0.7546323 df1
4 1  1.8358605 df2
5 2  0.9107199 df2
6 3  0.8313439 df2
7 1  0.5827148 df3
8 2 -0.9896495 df3
9 3 -0.9451503 df3

【问题讨论】:

  • 不完全是答案,但您可能对here 使用的各种方法感兴趣。
  • 不使用命名列表是在自取其辱。

标签: r plyr


【解决方案1】:

如果您想使用function,而不是deparse(substitute(x)),请使用match.call(),并且您需要第二个参数,请确保将其转换为character

 name <- as.character(match.call()[[2]])

【讨论】:

    【解决方案2】:

    使用名称定义您的列表,它应该为您提供一个带有 data.frame 名称的 .id

    df.list <- list(df1=df1, df2=df2, df3=df3)
    df.all <- ldply(df.list, rbind)
    

    输出:

      .id a           x
    1 df1 1  1.84658809
    2 df1 2 -0.01177462
    3 df1 3  0.58579469
    4 df2 1 -0.64748756
    5 df2 2  0.24384614
    6 df2 3  0.59012676
    7 df3 1 -0.63037679
    8 df3 2 -1.17416295
    9 df3 3  1.09349618
    

    那么你就可以从df.all$.id这一列知道data.frame的名字了

    编辑: 根据@Gary Weissman 的评论,如果您想自动生成名称,您可以这样做

    names(df.list) <- paste0('df',seq_along(df.list)
    

    【讨论】:

    • 我写的是同样的东西,除了do.call(rbind, df.list)而不是ldply,它也给出了原始行。
    • 这种方法的唯一缺点是您实际上必须手动输入所有数据帧的名称。你能做类似names(df.list) &lt;- paste0('df',seq_along(df.list))
    • +1 这真的很有帮助——本质上我的问题的答案是“使它成为一个命名列表”——但我很感激你走得更远!
    • @Gary Weissman - 这很好,因为它提供了一个唯一的标识符,但不链接到特定的名称。当然,一旦它是一个未命名的列表,就真的不可能建立那个链接了。
    • 很高兴它成功了。是的,关键是“named list”,您可以根据@Gary 的评论手动或自动提供名称
    【解决方案3】:

    仅使用 base,可以尝试以下操作:

    dd <- lapply(seq_along(df.list), function(x) cbind(df_name = paste0('df',x),df.list[[x]]))
    
    do.call(rbind,dd)
    

    【讨论】:

    • 嘿。我确实试过了,但那是在你真正完成编辑之前。有一段时间,你只有 lapply 排队(以及它的另一个版本),这肯定不起作用。
    • 啊抱歉,我的浏览器死机了,我的编辑被破坏了;-(
    • +1 每个元素至少有一个唯一的名称,但问题是每个元素都是按顺序命名的(即与数据框名称无关)。
    • @alexwhan 获取名称的替代方法可能是替换为 df_name = names(df.list)[x]
    【解决方案4】:

    在您的定义中,df.list 没有名称,但是,即使这样,deparse 替代成语似乎也无法轻松工作(因为lapply 调用.Internal(lapply(X, FUN)) - 您必须查看源代码才能看到对象名称是否可用以及如何获取它

    有点像

    names(df.list) <- paste('df', 1:3, sep = '')
    
    foo <- function(n, .list){
             .list[[n]]$id <- n
             .list[[n]]
           } 
    
         a          x id
    1 1  0.8204213  a
    2 2 -0.8881671  a
    3 3  1.2880816  a
    4 1 -2.2766111  b
    5 2  0.3912521  b
    6 3 -1.3963381  b
    7 1 -1.8057246  c
    8 2  0.5862760  c
    9 3  0.5605867  c
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-18
      • 2016-09-08
      • 1970-01-01
      • 1970-01-01
      • 2014-03-09
      • 2021-07-15
      相关资源
      最近更新 更多