【问题标题】:How to join/ merge two tables using character values?如何使用字符值连接/合并两个表?
【发布时间】:2015-07-09 12:19:16
【问题描述】:

我想根据名字、姓氏和年份组合两个表,并创建一个新的二进制变量,指示表 1 中的行是否存在于第二个表中。

第一张表是一个赛季NBA球员一些属性的面板数据集:

   firstname<-c("Michael","Michael","Michael","Magic","Magic","Magic","Larry","Larry")
   lastname<-c("Jordan","Jordan","Jordan","Johnson","Johnson","Johnson","Bird","Bird")
   year<-c("1991","1992","1993","1991","1992","1993","1992","1992")

   season<-data.frame(firstname,lastname,year)


    firstname   lastname        year
  1 Michael      Jordan         1991
  2 Michael      Jordan         1992
  3 Michael      Jordan         1993
  4 Magic        Johnson        1991
  5 Magic        Johnson        1992
  6 Magic        Johnson        1993
  7 Larry        Bird           1992
  8 Larry        Bird           1992

第二个data.frame是入选全明星赛的NBA球员的一些属性的面板数据集:

   firstname<-c("Michael","Michael","Michael","Magic","Magic","Magic")
   lastname<-c("Jordan","Jordan","Jordan","Johnson","Johnson","Johnson")
   year<-c("1991","1992","1993","1991","1992","1993")

    ALLSTARS<-data.frame(firstname,lastname,year)



     firstname  lastname    year
  1 Michael     Jordan    1991
  2 Michael     Jordan    1992
  3 Michael     Jordan    1993
  4 Magic       Johnson   1991
  5 Magic       Johnson   1992
  6 Magic       Johnson   1993

我想要的结果如下:

  firstname lastname    year    allstars

   1    Michael Jordan  1991    1
   2    Michael Jordan  1992    1
   3    Michael Jordan  1993    1
   4    Magic   Johnson 1991    1
   5    Magic   Johnson 1992    1
   6    Magic   Johnson 1993    1
   7    Larry   Bird    1992    0
   8    Larry   Bird    1992    0

我尝试使用左连接。但不确定这是否有意义:

    test<-join(season, ALLSTARS, by =c("lastname","firstname","year") , type = "left", match = "all")

【问题讨论】:

  • 我会使用 dplyr 包中的left_join 或right_join,就像大卫的回答一样。但是为了修复你的代码:看起来你正在使用 plyr 包中的join()。你快到了,只需在你的命令前加上ALLSTARS$allstars &lt;- 1。然后加入并将NA 值转换为0。
  • @Sam Firke。那简直是非凡的! :) 谢谢。完美运行!
  • 很高兴它有帮助 - 我已经把它写成下面的答案。

标签: r


【解决方案1】:

这是一个使用 data.table 二进制连接的简单解决方案,它允许您在连接时通过引用更新列

library(data.table)
setkey(setDT(season), firstname, lastname, year)[ALLSTARS, allstars := 1L]
season
#    firstname lastname year allstars
# 1:     Larry     Bird 1992       NA
# 2:     Larry     Bird 1992       NA
# 3:     Magic  Johnson 1991        1
# 4:     Magic  Johnson 1992        1
# 5:     Magic  Johnson 1993        1
# 6:   Michael   Jordan 1991        1
# 7:   Michael   Jordan 1992        1
# 8:   Michael   Jordan 1993        1

或使用dplyr

library(dplyr)
ALLSTARS %>% 
  mutate(allstars = 1L) %>%
  right_join(., season)
#   firstname lastname year allstars
# 1   Michael   Jordan 1991        1
# 2   Michael   Jordan 1992        1
# 3   Michael   Jordan 1993        1
# 4     Magic  Johnson 1991        1
# 5     Magic  Johnson 1992        1
# 6     Magic  Johnson 1993        1
# 7     Larry     Bird 1992       NA
# 8     Larry     Bird 1992       NA

【讨论】:

  • @大卫,非常感谢!我的例子在某种程度上具有误导性。您在示例中是否引用了列 allstars 或表 ALLSTARS
  • 使用我得到的第一个建议:Error in bmerge(i &lt;- shallow(i), x, leftcols, rightcols, io &lt;- haskey(i), : x.'firstname' is a character column being joined to i.'year' which is type 'integer'. Character columns must join to factor or character columns.
  • 我没有收到这些错误,但我建议您在创建数据集时使用stringsAsFactors = FALSE,如season&lt;-data.frame(firstname,lastname,year, stringsAsFactors = FALSE) 和ALLSTARS&lt;-data.frame(firstname,lastname,year, stringsAsFactors = FALSE)。顺便说一句,您使用的data.table 版本是什么?
  • 它在相应的数据类型中(first/lastname=chr)嗯好的thanx! 1.9.4
  • 我使用的是开发版(1.9.5),所以它可能已经修复了。
【解决方案2】:

在基础 R 中:

ALLSTARS$allstars <- 1L
newdf <- merge(season, ALLSTARS, by=c('firstname', 'lastname', 'year'), all.x=TRUE)
newdf$allstars[is.na(newdf$allstars)] <- 0L 
newdf

或者我喜欢另一种方法:

season$allstars <- (apply(season, 1, function(x) paste(x, collapse='')) %in%
apply(ALLSTARS, 1, function(x) paste(x, collapse='')))+0L
# 
#   firstname lastname year allstars
# 1   Michael   Jordan 1991        1
# 2   Michael   Jordan 1992        1
# 3   Michael   Jordan 1993        1
# 4     Magic  Johnson 1991        1
# 5     Magic  Johnson 1992        1
# 6     Magic  Johnson 1993        1
# 7     Larry     Bird 1992        0
# 8     Larry     Bird 1992        0

【讨论】:

    【解决方案3】:

    看起来您正在使用 plyr 包中的 join()。你快到了:只需在你的命令前加上ALLSTARS$allstars &lt;- 1。然后按照编写的方式进行连接,最后将 NA 值转换为 0。所以:

    ALLSTARS$allstars <- 1
    test <- join(season, ALLSTARS, by =c("lastname","firstname","year") , type = "left", match = "all")
    test$allstars[is.na(test$allstars)] <- 0
    

    结果:

      firstname lastname year allstars
    1   Michael   Jordan 1991        1
    2   Michael   Jordan 1992        1
    3   Michael   Jordan 1993        1
    4     Magic  Johnson 1991        1
    5     Magic  Johnson 1992        1
    6     Magic  Johnson 1993        1
    7     Larry     Bird 1992        0
    8     Larry     Bird 1992        0
    

    虽然我个人会使用 dplyr 包中的 left_join 或 right_join,如 David 的回答,而不是 plyr 的 join()。另请注意,在这种情况下,您实际上并不需要 join() 的 by 参数,因为默认情况下,该函数将尝试加入所有具有通用名称的字段,这正是您想要的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-10
      • 1970-01-01
      • 2018-10-18
      • 2019-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多