Можно ли выполнить полное соединение в dplyr и сохранить все столбцы, используемые в соединении?

У меня есть две таблицы, для которых я хочу выполнить полное соединение с помощью 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"))

person Dave Kincaid    schedule 05.05.2017    source источник
comment
Сообщил о проблеме здесь: github.com/rstudio/sparklyr/issues/663. Спасибо!   -  person kevinykuo    schedule 05.05.2017


Ответы (3)


Я не могу воспроизвести вашу проблему. Все идентификаторы должны быть (и включены) в полное соединение.

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. Это странное поведение, поэтому вы можете сообщить о проблеме. (Однако неясно, связана ли проблема с sparklyr, dplyr, DBI или 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
person Richie Cotton    schedule 05.05.2017
comment
Спасибо, что указали на это. Я должен был сначала попробовать это сам. Очень интересно. Это определенно не то поведение, которое я наблюдаю при использовании Sparklyr. Я создам пример кода, чтобы продемонстрировать и обновить свой вопрос. - person Dave Kincaid; 05.05.2017

Вы можете создать отдельные идентичные 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
person Psidom    schedule 05.05.2017
comment
Мне нравится эта идея, и я могу попробовать ее в качестве обходного пути. Однако, как указывает Ричи, это работает внутри самого dplyr. Поведение отличается, если используется спарклайр. - person Dave Kincaid; 05.05.2017
comment
Это должен быть принятый ответ - вопрос касается сохранения всех столбцов из обеих таблиц, что вам понадобится, если вы хотите проверить, какие строки не присоединились, а не только один столбец, содержащий все значений ключа соединения. Этот ответ - безусловно, самый простой способ добраться до этого. - person Charles Davis; 25.02.2019

Это было исправлено

> 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
person kevinykuo    schedule 16.05.2017