【问题标题】:Join two data frames based on one column of a frame and two columns of another基于框架的一列和另一列的两列连接两个数据框架
【发布时间】:2016-08-02 04:23:47
【问题描述】:

所以我有两个数据框,info 和 towers,示例如下:

信息:

ID             Date
1132           01/09/2015
1156           02/09/2015
1132           04/09/2015
1101           04/09/2015

塔楼:

Tower   ID1   ID2
    1   1132  1101
    2   1520  1156

Info 的 ID 列中的值将始终与 Towers 中的 ID1 或 ID2 匹配。我想根据这些信息加入框架,所以我加入的框架应该是:

ID             Date         Tower
1132           01/09/2015       1
1156           02/09/2015       2
1132           04/09/2015       1
1101           04/09/2015       2

我知道 dplyr 的 semi_join 可以满足我的需求,但我知道它需要值和列名匹配。鉴于这些列有不同的名称,我不知道它是否能正常工作。有什么方法可以在这里使用吗?

【问题讨论】:

  • melt Towers 所以您的 ID 在同一列中
  • 你应该看看as.Date 并学会正确地格式化它们。另外,请让您的示例下次可重现,以便其他人可以复制粘贴。
  • @Frank 是的,我已经在格式中工作过。出于学习目的,作为可重复的示例,您的确切含义是什么?
  • 我指的是下面 Sumedh 答案中的额外内容,看起来像 structure(...) 如果您将其复制粘贴到您的 R 会话中,它将返回您的示例 data.frame。这种事情应该包含在一个问题中。有关如何执行此操作的信息,请查看stackoverflow.com/questions/5963269/…

标签: r


【解决方案1】:
library(dplyr)

tidyr::gather(df2, Tower2, ID, -Tower) %>% select(-Tower2) %>% right_join(df, "ID")

df

structure(list(ID = c(1132, 1156, 1132, 1101), Date = structure(c(1L, 
2L, 3L, 3L), .Label = c("01/09/2015", "02/09/2015", "04/09/2015"
), class = "factor")), .Names = c("ID", "Date"), row.names = c(NA, 
-4L), class = "data.frame")

df2

structure(list(Tower = 1:2, ID1 = c(1132L, 1520L), ID2 = c(1101L, 
1156L)), .Names = c("Tower", "ID1", "ID2"), class = "data.frame", row.names = c(NA, 
-2L))

【讨论】:

    【解决方案2】:

    我们可以从data.table 使用melt。将 'data.frame' 转换为 'data.table' (setDT(df2)),将 melt 从 'wide' 转换为 'long' 格式和 join 与原始数据集 'df' on 'ID'。

    library(data.table)
    melt(setDT(df2), id.var="Tower", value.name = "ID")[df, on = "ID"][, variable := NULL][]
    #  Tower   ID       Date
    #1:     1 1132 01/09/2015
    #2:     2 1156 02/09/2015
    #3:     1 1132 04/09/2015
    #4:     1 1101 04/09/2015
    

    我们也可以在没有任何连接的情况下只使用base R(没有外部包,没有任何循环(sapply 是伪装的循环))。在这里,想法是通过除“塔”之外的列数复制第二个数据集“塔”列,即2,通过unlisting 设置该向量的names,将“df2”的列除外'Tower' (unlist(df2[-1])) 并使用它来匹配第一个数据集 (as.character(df$ID)) 中的 'ID' 列,以返回与 'ID' 对应的 'Tower'。

    df$Tower <- setNames( rep(df2$Tower, 2), unlist(df2[-1]))[as.character(df$ID)]
    df$Tower
    #[1] 1 2 1 1
    

    【讨论】:

      【解决方案3】:

      你真的不需要加入;只要您按行分组评估,您就可以创建一个新列:

      Info %>% rowwise() %>% 
          mutate(Tower = Towers[ID == Towers$ID1 | ID == Towers$ID2, 'Tower'])
      ## Source: local data frame [4 x 3]
      ## Groups: <by row>
      ## 
      ## # A tibble: 4 x 3
      ##      ID       Date Tower
      ##   <int>     <fctr> <int>
      ## 1  1132 01/09/2015     1
      ## 2  1156 02/09/2015     2
      ## 3  1132 04/09/2015     1
      ## 4  1101 04/09/2015     1
      

      或等价于全基 R,

      Info$Tower <- sapply(Info$ID, function(x){Towers[x == Towers$ID1 | x == Towers$ID2, 'Tower']})
      

      【讨论】:

        【解决方案4】:

        另一种方法使用reshape2 包中的melt(@SymbolixAU 在评论中也建议)并使用@Sumedh 帖子的dfdf2

        library(reshape2)
        library(dplyr)
        melt(df2,value.name = "ID",id.vars = "Tower") %>% right_join(df,by = "ID") %>% select(-variable)
        

        我们也可以通过使用base R reshape 函数来做到这一点:

        reshape(data = df2,direction = "long",varying = c("ID1","ID2"),v.names = "ID") %>% right_join(df,by = "ID") %>% select(-c(time,id))
        

        【讨论】:

          猜你喜欢
          • 2023-04-05
          • 1970-01-01
          • 2022-12-01
          • 2021-01-11
          • 2022-01-16
          • 1970-01-01
          • 2022-11-03
          • 2021-04-21
          • 1970-01-01
          相关资源
          最近更新 更多