C-/R-Bind 来自数据表列表,不回收,w/ 使用列表名称作为列名的一部分

c-/r-bind from a list of data tables w/o recycling and w/ using list names as part of col names

提问人:MarkH 提问时间:9/20/2023 最后编辑:MarkH 更新时间:9/22/2023 访问量:52

问:

有很多帖子阐明了我问题的各个部分,但我无法将其混淆在一起,需要帮助。我正在尝试从数据表列表中绑定许多具有不同行数但相同的列计数和名称的数据表,但是:

  1. 我不想从行数较少的表中回收行
  2. 我确实想使用列表项名称从结果表中的“边框”列创建单个列
  3. 我不想使用列表项名称,也不想从结果表中的所有“值”列创建单个列

以下是从其他帖子中获取的小示例和各种部分解决方案:

# Create dummy list of data frames    
df1 <- data.frame(border=c(1,2,3), value=c(4,5,6))
df2 <- data.frame(border=as.factor(c("A","B")), value=c(3,5.7))
df_lst <- list(df1, df2)
names(df_lst) <- c("df1","df2")


t1 <- as.data.table(df_lst)
t2 <- DataVisualizations::CombineCols(df1, df2)
t3 <- do.call(CombineCols,as.data.table(df_lst))
t4 <- rbindlist(df_lst)

谁能帮我解决这个问题,这样我就可以使用列表(而不是我在现实生活中没有的单个数据帧)作为唯一的输入来获得这样的东西......

   df1 df2 value
1:   1 NA    4
2:   2 NA    5
3:   3 NA    6
4:  NA  A   3.0
5:  NA  B   5.7

任何提示都值得赞赏!

干杯 马克

r 列表 应用 rbind cbind

评论


答:

1赞 Maël 9/20/2023 #1

您可以使用 data.frame 的名称重命名第一列,然后使用 (或者,如果您愿意,):mapplydplyr::bind_rowsdata.table::rbindfill(fill = TRUE)

df_lst |> 
  mapply(FUN = \(x, y){names(x)[1] <- y; x}, 
         x = _, y = names(df_lst), SIMPLIFY = FALSE) |> 
  dplyr::bind_rows()

#   df1 value  df2
# 1   1   4.0 <NA>
# 2   2   5.0 <NA>
# 3   3   6.0 <NA>
# 4  NA   3.0    A
# 5  NA   5.7    B

评论

1赞 MarkH 9/20/2023
这看起来很酷,并将在我的现实生活中的数据集上进行测试。谢谢!
0赞 MarkH 9/20/2023
即使使用相对较大的数据集,它也能很好地工作:-)我有没有可能挤进去,第 3 列和第 4 列(存在于每个 dfs 中,但不是必需的)可以立即作为 mapply 的一部分删除?
0赞 MarkH 9/20/2023
我自己想通了: 我可以简单地将标准 lapply 添加到管道中,作为仅选择特定列的第一步,如下所示:|> lapply("[", , c(".value",".borders"))
0赞 smacks 9/20/2023 #2

我不确定我是否理解了您不想要的内容,但我设法使用基础 R 获得了您想要的输出。

  1. 使用 for 循环(可能有更好的方法,例如使用 lapply)将 DataFrame 的列重命名为 “border”,以便它采用所需的 DataFrame 的名称。(不确定这是否是你不想要的第二点)
  2. 使用 Reduce 合并列表的 DataFrame。它还应该适用于两个以上的数据帧。
df1 <- data.frame(border=c(1,2,3), value=c(4,5,6))
df2 <- data.frame(border=as.factor(c("A","B")), value=c(3,5.7))
df_lst <- list(df1, df2)
list_names <- c("df1","df2")
names(df_lst) <- list_names

for(i in list_names) {
  names(df_lst[[i]])[which(names(df_lst[[i]]) == "border")] <- i
  # works fine if you just want to specify position of column and not name :
  # names(df_lst[[i]])[1] <- i
}

df_lst <- Reduce(
            function(df1,df2) {
               merge(
                 df1,
                 df2,
                 by = c("value"),
                 all = TRUE
               )
             },
             df_lst
            )

> print(df_lst)
  value df1  df2
1   3.0  NA    A
2   4.0   1 <NA>
3   5.0   2 <NA>
4   5.7  NA    B
5   6.0   3 <NA>

希望这有帮助!

编辑:意识到如果“值”列中有相同的值,就会出现问题,合并可能不是解决方案。例如,具有不同的值:

df1 <- data.frame(border=c(1,2,5,3), value=c(4,5,5,6))
df2 <- data.frame(border=as.factor(c("A","B","C")), value=c(3,5.7,5))

> df_lst
  value df1  df2
1   3.0  NA    A
2   4.0   1 <NA>
3   5.0   2    C # you get C twice
4   5.0   5    C # you get C twice
5   5.7  NA    B
6   6.0   3 <NA>

评论

0赞 MarkH 9/20/2023
谢谢,但实际上我正在处理数百列,所以我想避免 for 循环
0赞 Jakub Małecki 9/22/2023
请注意格式化代码,使其更具可读性,并使用 R 编码约定:间距和赋值运算符
0赞 smacks 9/22/2023
好的,快速编辑格式。以后会更加小心。谢谢