【问题标题】:Merging multiple data frames in a list to another data frame by various columns通过不同的列将列表中的多个数据框合并到另一个数据框
【发布时间】:2018-10-28 19:09:05
【问题描述】:

在我的代码中,我使用了多个 left_join 将单独的数据帧合并到我正在处理的 dplyr 链中。我将要与另一个合并的数据框导入到一个列表中,然后使用 lapply 直接在该列表上进行一些操作以准备合并。

到目前为止,我已经使用 list2env(list, envir = .GlobalEnv) 从列表中创建单独的数据框,然后使用 left_join 通过每个数据框的唯一列分别合并每个数据框,如下所示:

测试数据:

列表:

structure(list(df2 = structure(list(x = structure(c(2L, 1L, 3L
), .Label = c("A", "B", "C"), class = "factor"), a = c(-0.331543943439452, 
0.0588350184156617, 1.03657229544754)), .Names = c("x", "a"), row.names = c(NA, 
-3L), class = "data.frame"), df3 = structure(list(z = structure(c(3L, 
2L, 1L), .Label = c("K", "L", "M"), class = "factor"), b = c(-0.897094152848114, 
0.97612075490695, 0.650264147064918)), .Names = c("z", "b"), row.names = c(NA, 
-3L), class = "data.frame")), .Names = c("df2", "df3"))

创建单独的数据框:

list2env(testlist, envir = .GlobalEnv)

数据框:

structure(list(x = structure(1:3, .Label = c("A", "B", "C"), class = "factor"), 
    y = 1:3, z = structure(1:3, .Label = c("K", "L", "M"), class = "factor")), .Names = c("x", 
"y", "z"), row.names = c(NA, -3L), class = "data.frame")

加入:

library(dplyr)

test_df %>%
    left_join(., df2, by = "x") %>%
    left_join(., df3, by = "z")

(请注意,我的列表大约有 8 个数据框,每个数据框有 2 - 3 列。为简单起见,我在此列表中只包含了两个数据框)

所有数据框都有自己单独的“by”列。 我想知道是否有更简单的方法可以做到这一点,f。 ex 通过直接与整个列表合并,并自动检测哪些列相似并为每个数据帧合并,而不是分别进行八次 left_join?

编辑

按照@akrun 的建议,我尝试运行以下代码:

out <- test
for(i in seq_along(table_list)) {
  nm1 <- intersect(names(out), names(table_list[[i]]))
  out <- merge(out, table_list[[i]], by = nm1)
}
out

其中test 是要合并到的数据框,table_list 是数据框列表。 这适用于这些小型测试数据帧,但似乎会在数据帧中引入重复的单个行,从而导致更多行。

更复杂的示例数据框:

structure(list(x = structure(c(1L, 2L, 3L, 4L, 1L, 2L, 3L, 4L
), .Label = c("A", "B", "C", "D"), class = "factor"), y = c(1, 
2, 3, 4, 1, 2, 3, 4), z = structure(c(1L, 2L, 3L, 1L, 2L, 3L, 
1L, 2L), .Label = c("K", "L", "M"), class = "factor")), .Names = c("x", 
"y", "z"), row.names = c(NA, -8L), class = "data.frame")

【问题讨论】:

  • 我有一个疑问,您是否基于list 中的元素数量计算了by 列的数量。我的意思是你的 8 data.frame 列表
  • 或许out&lt;- test_df;nm1 &lt;- c("x", "z"); for(i in seq_along(nm1)) out &lt;- merge(out, testlist[[i]], by = nm1[i], all.x= TRUE)
  • @akrun 不太清楚你的意思,但我在列表中的每个数据框都以唯一的名称命名,并且它们的长度各不相同。
  • 您能否使可重现的示例更复杂一些,以便它在 for 循环代码中提供重复项。如果没有显示问题的示例,我无法对其进行测试\
  • 我还在merge中添加了all.x = TRUE

标签: r


【解决方案1】:

使用复杂的test_df,为什么不使用来自purrrreduce和来自dplyr的left_join呢?我在下面的代码中包含了消息和警告消息。

library(dplyr)
library(purrr)

all_dfs <- reduce(my_list, left_join, .init = test_df)

# (warning) messages from using left_join
# Joining, by = "x"
# Joining, by = "z"
# Warning message:
# Column `x` joining factors with different levels, coercing to character vector 

all_dfs

  x y z           a          b
1 A 1 K  0.05883502  0.6502641
2 B 2 L -0.33154394  0.9761208
3 C 3 M  1.03657230 -0.8970942
4 D 4 K          NA  0.6502641
5 A 1 L  0.05883502  0.9761208
6 B 2 M -0.33154394 -0.8970942
7 C 3 K  1.03657230  0.6502641
8 D 4 L          NA  0.9761208

【讨论】:

  • 简单而精彩 - 谢谢!
【解决方案2】:

根据描述,我们似乎需要在每个merge之前检查相交的列名

out <- test_df
for(i in seq_along(testlist)) {
   nm1 <- intersect(names(test_df), names(testlist[[i]]))
   out <- merge(out, testlist[[i]], by = nm1, all.x = TRUE)
 }

out
#  z x y           a          b
#1 K A 1  0.05883502  0.6502641
#2 L B 2 -0.33154394  0.9761208
#3 M C 3  1.03657230 -0.8970942

【讨论】:

  • 这似乎可行,但是我自己的数据框从 853 行变为 2760。这不应该添加更多行,不是吗?
  • 另外,有没有办法用 dplyr 做到这一点?我希望将它包含在我的链中
  • @Haakonkas 这可能是因为合并列的重复 ID。你用你展示的方式试过了吗\
  • @Haakonkas 你能试试把intersect(names(test_df),改成intersect(names(out),
  • 我仍然得到相同的结果,创建了额外的行。我检查了数据框中的重复项,但没有。但是,当我运行上述时会产生重复
猜你喜欢
  • 2012-11-14
  • 1970-01-01
  • 1970-01-01
  • 2017-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-18
  • 1970-01-01
相关资源
最近更新 更多