【问题标题】:Merge Two Lists of Data Frames by ID and DATE in R在R中按ID和DATE合并两个数据框列表
【发布时间】:2018-09-20 17:11:46
【问题描述】:

我需要通过两个关键变量 ID 和 DATE 合并两个数据框列表。这是我拥有的数据示例:

 names1 <- c("df1", "df2")
 mydf1 <- data.frame(ID=c(115477, 115477), DATE=c("2012-01-31","2012-02-   29"), SCORE =c(677,635)) 
 mydf2 <- data.frame(ID=c(22319, 22319), DATE=c("2011-09-30","2011-10-31"), SCORE = c(621,630))
 list1 <- list(mydf1,mydf2)
 names(list1) <- names1

 names2 <- c("df_auto1", "df_auto2")
 mydf_auto1 <- data.frame(ID=c(22319, 22319),DATE=c("2011-09-30","2011-10-31") , Fprice =c(8708,8708)) 
 mydf_auto2 <- data.frame(ID=c(115477, 115477), DATE=c("2012-01-31","2012-02-29"), Fprice = c(NA,6543))
 list2 <- list(mydf_auto1,mydf_auto2)
 names(list2) <- names2

我尝试使用 Map 功能,但我得到的输出搞砸了。这是我尝试做的:

 V <-Map(merge, list1, list2,MoreArgs=list(by=c('ID','DATE'), all=TRUE))

 for (i in seq_along(V)) {
 write.csv(V[[i]], paste0("merge_",i, ".csv"))
 }

作为最终输出,我想获得一个 ID = 115477 和完全填充变量(例如 DATE、SCORE 和 Fprice)的数据帧;另一个 ID = 22319 且完全填充的数据框。例如,对于 ID = 115477,我想得到:

  ID        DATE          SCORE    Fprice
 115477    2012-01-31     677     NA
 115477    2012-02-29     635     6543 

有人知道我做错了什么吗?感谢您的帮助。

【问题讨论】:

  • 你可以试试merge( do.call(rbind, list1), do.call(rbind, list2), by=c('ID', 'DATE'), all=TRUE )
  • 您好 chinsoon12,非常感谢您的建议。您的解决方案是完美的!我虽然对 rbind 感到担忧。我的数据非常庞大。 rbind 命令将所有数据帧组合在一起。无论如何要保留数据框列表吗?
  • 我想,我会采用以下解决方案:V

标签: r list dataframe merge


【解决方案1】:

你会更容易做一个merge,然后单独提取你想要的ID

names1 <- c("df1", "df2")
mydf1 <- data.frame(ID=c(115477, 115477), DATE=c("2012-01-31","2012-02-29"), SCORE =c(677,635)) 
mydf2 <- data.frame(ID=c(22319, 22319), DATE=c("2011-09-30","2011-10-31"), SCORE = c(621,630))
# Note the change to use of rbind instead of list
list1 <- rbind(mydf1, mydf2)

names2 <- c("df_auto1", "df_auto2")
mydf_auto1 <- data.frame(ID=c(22319, 22319),DATE=c("2011-09-30","2011-10-31") , Fprice =c(8708,8708)) 
mydf_auto2 <- data.frame(ID=c(115477, 115477), DATE=c("2012-01-31","2012-02-29"), Fprice = c(NA,6543))
list2 <- rbind(mydf_auto1,mydf_auto2)

df <- merge(list1, list2, by = c("ID", "DATE"))
df[df$ID == 115477,]
df[df$ID == 22319, ]

【讨论】:

  • 嗨whalea,非常感谢您提出这个解决方案。我虽然收到了一条错误消息: > K
  • @Yelena 你的list1list2 都有IDDATE 列吗?您可以通过运行names(list1)names(list2) 来仔细检查。如果您的列表中的任何一个不完全包含这两个列,则它将不起作用
  • 是的,两者都有“ID”和“DATE”。
  • list1 中是否有 IDDATE 完全相同的行? list2 的同样问题。因为如果是这样的话,你将无法如此直接地合并它们
  • 我目前正在使用此问题中描述的确切示例。
【解决方案2】:

这是tidyverse 方法:

library(tidyverse);
list(bind_rows(list1), bind_rows(list2)) %>%
    reduce(function(x, y) full_join(x, y, by = c("ID", "DATE"))) %>%
    filter(ID %in% c(115477))
#      ID       DATE SCORE Fprice
#1 115477 2012-01-31   677     NA
#2 115477 2012-02-29   635   6543

解释:对于每个list,我们将行绑定到一个data.frame;我们将两个折叠的data.frames 收集到list 中,然后通过"ID""DATE" 执行外连接;我们使用dplyr::filter 拉出感兴趣的行(这里是ID==115477)。

【讨论】:

  • 您好 Maurits Evers,非常感谢您提出此解决方案。它确实有效,但在运行它时我收到了 6 条警告消息。我应该担心什么吗?例如,1:在 bind_rows_(x, .id) 中:不等因子级别:强制转换为字符 2:在 bind_rows_(x,.id) 中:绑定字符和因子向量,强制转换为字符向量 3:在 bind_rows_(x, . id) : 绑定字符和因子向量,强制转换成字符向量
  • @Yelena 在这种情况下,警告是完全无害的,可以忽略。它们在合并时源自factorcharacter 的转换。如果您使用参数stringsAsFactors = FALSE 构造data.frames,则可以完全避免它们。
  • @Yelena [继续] 或者,您也可以全局设置options(stringsAsFactors=FALSE),这意味着在您创建的每个data.framecharacter 列将不会转换为factors。 tibbles(来自tidyverse)永远不会执行这种(通常是不希望的)隐式characterfactor 的转换。因此,如果您完全在 tidyverse 内工作(从数据生成到操作),您看到的警告将不会出现。
  • 非常非常感谢。我现在知道了。很有帮助。
【解决方案3】:

概述

mapply() 内部执行merge()

最终结果是一个包含两个数据帧的列表,每个数据帧都是 list2 中的第 jth 元素的结果,outer joined 中的第 ith 元素list1.

注意:mydf1 内的第二个 DATE 元素中有一个错字,已在下面更正。我的答案取决于list1list2 的内容是否拥有包含相同ID 值且顺序相同的数据帧。正如 OP 安排的那样,mydf_auto2 被设置为合并到mydf1;而mydf_auto2 应该基于这两个共享相同ID 值的数据帧合并到mydf2。我修改了list2 中的排序以产生所需的输出。

# create first list of data frames
names1 <- c("df1", "df2")
# note the extra spacing in "2012-02-29" has been corrected
mydf1 <- data.frame(ID=c(115477, 115477), DATE=c("2012-01-31","2012-02-29"), SCORE =c(677,635)) 
mydf2 <- data.frame(ID=c(22319, 22319), DATE=c("2011-09-30","2011-10-31"), SCORE = c(621,630))
list1 <- list(mydf1,mydf2)
names(list1) <- names1

# create second list of data frames
names2 <- c("df_auto1", "df_auto2")
# here is where I relabel the data frames
# to sync with `mydf1` and `mydf2` based on 
# the `ID` values contained in `mydf_auto1` and `mydf_auto2`
mydf_auto1 <- data.frame(ID=c(115477, 115477), DATE=c("2012-01-31","2012-02-29"), Fprice = c(NA,6543))
mydf_auto2 <- data.frame(ID=c(22319, 22319),DATE=c("2011-09-30","2011-10-31") , Fprice =c(8708,8708)) 
list2 <- list(mydf_auto1,mydf_auto2)
names(list2) <- names2

# merge the list of data frames together
merged.list.of.dfs <-
  mapply( FUN = function( i, j )
    merge( x = i
           , y = j
           , by = c( "ID", "DATE" )
           , all = TRUE )
    , list1
    , list2
    , SIMPLIFY = FALSE )

# view results
merged.list.of.dfs
# $df1
#       ID       DATE SCORE Fprice
# 3 115477 2012-01-31   677     NA
# 4 115477 2012-02-29   635   6543
# 
# $df2
#      ID       DATE SCORE Fprice
# 1 22319 2011-09-30   621   8708
# 2 22319 2011-10-31   630   8708

# end of script #

【讨论】:

  • 非常感谢您帮助我。你的方法很有趣。但是,我想得到一个稍微不同的输出。我想看到一个数据框列表,在 df1(比如,ID = 22319)中,我已经完全填充了分数和 Fprice。
  • @Yelena,请查看我修改后的答案,该答案可提供您的预期输出。
  • @Yelena 谢谢!感谢您澄清预期的输出。
猜你喜欢
  • 1970-01-01
  • 2018-05-20
  • 1970-01-01
  • 2018-04-08
  • 2015-11-06
  • 2021-07-05
  • 2017-09-10
  • 1970-01-01
  • 2020-10-16
相关资源
最近更新 更多