【问题标题】:Is it possible to do a full join in dplyr and keep all the columns used in the join?是否可以在 dplyr 中进行完全连接并保留连接中使用的所有列?
【发布时间】:2017-10-04 04:23:42
【问题描述】:

我有两个表,我想使用 dplyr 进行完全连接,但我不希望它删除任何列。根据文档和我自己的经验,它只保留左侧的连接列。由于连接值消失了,当您在右侧有一行记录时,这是一个问题。

例如,假设我有两个表a和b,

customerId | revenue               customerId | state
-----------|---------              -----------|-------
    1      | 2000                       1     |  CA
    2      | 3000                       3     |  GA
    4      | 4000                       4     |  NY

full_join(a, b, by="customerId") 这样的操作会产生

customerId | revenue | state
-----------|---------|-------
    1      |   2000  |  CA
    2      |   3000  | <NA>
   <NA>    |   <NA>  |  GA
    4      |   4000  |  NY

因此无法判断第三行来自哪个客户。理想的输出是

customerId.a | customerId.b | revenue | state
-------------|--------------|---------|-------
      1      |      1       |   2000  |  CA
      2      |     <NA>     |   3000  | <NA>
    <NA>     |      3       |   <NA>  |  GA
      4      |      4       |   4000  |  NY

请注意,这只是一个玩具示例。我实际上正在使用 sparklyr,所以这一切都在 Spark 中运行。因此,合并对我来说在这里不起作用。有没有办法做我在 dplyr 中寻找的东西?

编辑: 正如有人指出的那样,这实际上在 dplyr 本身在本地工作。但是,我确实使用 sparklyr(使用 dplyr)看到了这个问题。这是查看的代码:

library(sparklyr)
sc <- spark_connect("local[4]")
d1 <- data_frame(customerId = c("1","2","4"), revenue=c(2000,3000,4000))
d2 <- data_frame(customerId = c("1","3","4"), state=c("CA", "GA", "NY"))
d1_tbl <- copy_to(sc, d1)
d2_tbl <- copy_to(sc, d2)
full_join(d1_tbl, d2_tbl, by=c("customerId"))

【问题讨论】:

标签: r dplyr sparklyr


【解决方案1】:

只需在dplyr::full_join()中使用参数keep即可。

full_join(a, b, by="customerId",keep = TRUE)

【讨论】:

    【解决方案2】:

    这个问题已经解决了

    > full_join(d1_tbl, d2_tbl, by="customerId")
    # Source:   lazy query [?? x 3]
    # Database: spark_connection
      customerId revenue state
           <chr>   <dbl> <chr>
    1          1    2000    CA
    2          3     NaN    GA
    3          2    3000  <NA>
    4          4    4000    NY
    

    【讨论】:

      【解决方案3】:

      我无法重现您的问题。所有的 ID 都应该(并且现在)包含在完全连接中。

      library(data_frame)
      d1 <- data_frame(
        customerId = c(1, 2, 4),
        revenue = c(2000, 3000, 4000)
      )
      d2 <- data_frame(
        customerId = c(1, 3, 4),
        state = c("CA", "GA", "NY")
      )
      
      full_join(d1, d2, by = "customerId")
      ## # A tibble: 4 × 3
      ##   customerId revenue state
      ##        <dbl>   <dbl> <chr>
      ## 1          1    2000    CA
      ## 2          2    3000  <NA>
      ## 3          4    4000    NY
      ## 4          3      NA    GA
      

      更新:我可以使用sparklyr 重现该问题。这是一种奇怪的行为,因此您可能需要提出问题。 (不清楚问题出在sparklyrdplyrDBI 还是Spark SQL 上。)

      使用explain(),可以看到生成的SQL。

      full_join(d1_tbl, d2_tbl, by=c("customerId")) %>% explain()
      

      您可以尝试运行自定义 SQL 查询来获得您想要的结果,尽管它有点混乱。

      library(DBI)
      qry <- "SELECT 
          d1.customerID AS customerID1, 
          d2.customerID AS customerID2, 
          d1.revenue, 
          d2.state 
        FROM d1 
        FULL JOIN d2 
          ON d1.customerId = d2.customerId"
      dbGetQuery(sc, qry)  
      ##   customerID1 customerID2 revenue state
      ## 1           1           1    2000    CA
      ## 2           2        <NA>    3000  <NA>
      ## 3        <NA>           3     NaN    GA
      ## 4           4           4    4000    NY
      

      【讨论】:

      • 感谢您指出这一点。我应该先自己尝试一下。很有意思。这绝对不是我使用 sparklyr 看到的行为。我将创建一个代码示例来演示和更新我的问题。
      【解决方案4】:

      您可以在加入之前为两个数据框分别创建相同的customerId

      full_join(
          mutate(a, customerId.a = customerId), 
          mutate(b, customerId.b = customerId), 
          by="customerId"
      ) %>% select(-customerId)
      
      #  revenue customerId.a state customerId.b
      #1    2000            1    CA            1
      #2    3000            2  <NA>           NA
      #3    4000            4    NY            4
      #4      NA           NA    GA            3
      

      【讨论】:

      • 我喜欢这个想法,可以尝试一下。然而,正如 Richie 指出的那样,这确实在 dplyr 本身内部起作用。尽管使用 sparklyr,但行为有所不同。
      • 这应该是公认的答案 - 问题询问是否保留两个表中的所有 columns,如果您想检查哪些行没有加入,则需要这些,而不仅仅是包含连接键的所有值的一列。这个答案是迄今为止最简单的方法。
      猜你喜欢
      • 2020-04-25
      • 2020-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-02
      • 2017-02-23
      • 1970-01-01
      相关资源
      最近更新 更多