【问题标题】:rbind all data frames with common names based on list using lapplyrbind 使用 lapply 基于列表的通用名称的所有数据帧
【发布时间】:2018-06-04 14:14:33
【问题描述】:

我有几个这样命名的数据框:

orange_ABC
orange_BCD
apple_ABC
apple_BCD
grape_ABC
grape_BCD

我需要rbind 那些名称的第一部分有共同之处(橙子、苹果、葡萄)的人,并将新的数据框命名为这样。我正在从数据框列表names(fruitlist)(我从中制作上述数据框)中访问名称,并尝试使用lapplyfunction(x),但没有成功。我对 R 有点陌生,所以认为我在动态命名新数据框时犯了一个简单的错误......

lapply(names(fruitlist),
       function(x){
         frame_nm <- toString((names(fruitlist[x])))
         frame_nm <- do.call(rbind, mget(ls(pattern=paste0((names(splitlist[x])),"*"))))
})

我已经在一种“水果”上尝试了独立行,它似乎有效:

test_DF <- do.call(rbind, mget(ls(pattern="apple*")))

编辑:我意识到我忘了提到 6 个数据框的示例列表是动态创建的,所以我不能简单地生成它们的列表。但是,我确实有一个“水果”列表,并且所有可能的新数据框名称的结尾都是已知的(“_ABC”和“_BCD”)。

【问题讨论】:

  • 根据您的编辑,我做了一些更改,可能会根据您在全球环境中存在的数据框来满足您的需求。

标签: r lapply rbind


【解决方案1】:

正如怀疑的那样,为对象分配值的建议方法不起作用。此外,在使用ls()mget() 列出和访问函数内的命名对象时必须小心,因为除非另有说明,否则它们不会自动上升到父环境并且只能“看到”本地范围内的变量。这适用于 R 版本 3.4,旧版本的行为可能有所不同。

  1. 创建命名对象。

    为了在全局环境中创建新对象,请使用assign()(已在 Luke C 的回答中建议):

    > assign("foo", "some text")
    > foo
    [1] "some text"
    

    将代码放在函数中会产生局部作用域。显式指定全局环境允许设置全局变量:

    > set_foo <- function (x) { assign("foo", x, envir=globalenv()) }
    > set_foo("other text")
    > foo
    [1] "other text"
    

    请注意,省略 envir 参数将使全局环境不受影响。

  2. 在本地函数中使用ls()/mget()

    默认情况下,这仅列出该函数的当前(本地)环境中的名称,该函数仅在问题中给出的示例代码中看到参数x。与上面类似,快速解决方法是通过添加参数envir=globalenv() 显式指定全局环境。这同样适用于mget()

由于没有提供 MWE,我冒昧地改编了 Luke C 的答案中提供的“假数据”示例代码。

# Populate environment
namelist <- paste(fruit = rep(c("orange", "apple", "grape"), 2), 
                  nums =  rep(c("_ABC", "_BCD"), each =  3), sep = "")
for(x in namelist)
  assign(x, data.frame(a = 1:4, b = 11:14))

# The following re-generates the list of fruits used above
grouplist <- unique(unlist(lapply(strsplit(namelist, "_"), function (x) { x[[1]] })))
# Group and rbind by prefix, suppressing output
invisible(lapply(grouplist,
       function(x) {
         grouped <- do.call(rbind,
           mget(ls(pattern=paste0(x,"_*"), envir=globalenv()),
             envir=globalenv()))
         assign(x, grouped, envir=globalenv())
}))

【讨论】:

    【解决方案2】:

    如果您的 fruitlist 是数据框的命名列表,也许这会适合。

    首先,将相似的名字放入他们自己的列表中:

    fruit.groups <- split(names(fruitlist), 
                          sapply(strsplit(names(fruitlist), split = "_"), "[[", 1))
    
    > fruit.groups
    $apple
    [1] "apple_ABC" "apple_BCD"
    
    $grape
    [1] "grape_ABC" "grape_BCD"
    
    $orange
    [1] "orange_ABC" "orange_BCD"
    

    然后,按组使用lapplyrbind

    fdf <- lapply(fruit.groups, function(x){
      out <- do.call(rbind, fruitlist[x])
      out$from <- gsub("(\\..*)", "", rownames(out))
      rownames(out) <- NULL
      return(out)
    })
    
    > fdf$apple
      a  b      from
    1 1 11 apple_ABC
    2 2 12 apple_ABC
    3 3 13 apple_ABC
    4 4 14 apple_ABC
    5 1 11 apple_BCD
    6 2 12 apple_BCD
    7 3 13 apple_BCD
    8 4 14 apple_BCD
    

    假数据:

    namelist <- paste(fruit = rep(c("orange", "apple", "grape"), 2), 
                      nums =  rep(c("_ABC", "_BCD"), each =  3), sep = "")
    
    fruitlist <- llply(namelist, function(x){
      assign(as.character(x), data.frame(a = 1:4, b = 11:14))
    })
    

    编辑:

    根据您对上述问题的修改:

    如果您有水果和后缀,请使用expand.grid 获取所有可能的组合(假设所有组合都将引用动态生成的数据帧)。

    fruits <- c("orange", "apple", "grape")
    suffixes <- c("_ABC", "_BCD")
    fullnames <- apply(expand.grid(fruits, suffixes), 1, paste, collapse = "")
    

    使用该名称列表,使用mget 生成当前数据帧的列表。

    new_fruit_df_list <- mget(fullnames)
    

    那么,上面的代码应该可以工作了,在这里修改以反映名称的变化:

    fruit.groups <- split(names(new_fruit_df_list),
                          sapply(strsplit(names(new_fruit_df_list), split = "_"), "[[", 1))
    
    fdf <- lapply(fruit.groups, function(x){
      out <- do.call(rbind, new_fruit_df_list[x])
      out$from <- gsub("(\\..*)", "", rownames(out))
      rownames(out) <- NULL
      return(out)
    })
    

    查看每个标题,添加的列(如果您不想要,请删除)显示该行的原始数据框的名称。

    > lapply(fdf, head, 2)
    $apple
      a  b      from
    1 1 11 apple_ABC
    2 2 12 apple_ABC
    
    $grape
      a  b      from
    1 1 11 grape_ABC
    2 2 12 grape_ABC
    
    $orange
      a  b       from
    1 1 11 orange_ABC
    2 2 12 orange_ABC
    

    【讨论】:

      【解决方案3】:

      试试这个:

      file_groups <- ls()[grep(".*_.*", ls())]
      file_groups <- gsub("(.*)_.*", "\\1", file_groups)
      df_list <- lapply(file_groups, 
                        function(x){ do.call(rbind, mget(ls(pattern = paste0(x, "*"))))})
      

      【讨论】:

        猜你喜欢
        • 2013-05-08
        • 2020-04-04
        • 2017-06-08
        • 1970-01-01
        • 1970-01-01
        • 2015-04-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多