Объединить два R-кадра данных, используя хотя бы один идентификатор объединения по столбцам - PullRequest
1 голос
/ 10 октября 2019

У меня есть проблема с соединением, с которой я борюсь, потому что идентификаторы соединений, которые я хочу использовать для отдельных фреймов данных, распределены по трем возможным столбцам идентификаторов. Я хотел бы иметь возможность присоединиться, если хотя бы один идентификатор присоединения соответствует. Я знаю, что функции _join и merge принимают вектор имен столбцов, но возможно ли сделать эту работу условно?

Например, если у меня есть следующие два фрейма данных:

df_A <- data.frame(dta = c("FOO", "BAR", "GOO"),
                   id1 = c("abc", "", "bcd"),
                   id2 = c("", "", "xyz"),
                   id3 = c("def", "fgh", ""), stringsAsFactors = F)


df_B <- data.frame(dta = c("FUU", "PAR", "KOO"),
                   id1 = c("abc", "", ""),
                   id2 = c("", "xyz", "zzz"),
                   id3 = c("", "", ""), stringsAsFactors = F)


> df_A
 dta id1 id2 id3
1 FOO abc     def
2 BAR         fgh
3 GOO bcd xyz   

> df_B
  dta id1 id2 id3
1 FUU abc        
2 PAR     xyz    
3 KOO     zzz  

Я надеюсь, что в итоге получится что-то вроде этого:

 dta.x dta.y id1  id2  id3  
1 FOO  FUU   abc  ""   def    [matched on id1]
2 BAR  ""    ""   ""   fgh      [unmatched]
3 GOO  PAR   bcd  xyz  ""    [matched on id2]
4 KOO  ""    ""   zzz  ""      [unmatched]

Таким образом, сохраняются несопоставленные переменные dta1 и dta1, но там, где есть совпадение (строка 1 + 3 выше), оба dta1 и dta2 объединяются в новомТаблица. У меня есть ощущение, что ни _join, ни merge, ни match не будут работать как есть, и мне нужно написать функцию, но я не уверен, с чего начать. Любая помощь или идеи приветствуются. Спасибо

Ответы [ 2 ]

1 голос
/ 10 октября 2019
library(sqldf)
one <- 
  sqldf('
    select  a.*
            , b.dta as dta_b
    from    df_A a
            left join df_B b
              on  a.id1 <> ""
                  and (
                    a.id1 = b.id1
                    or a.id2 = b.id2)

  ')

two <- 
  sqldf('
    select  b.*
    from    df_B b
            left join one
              on  b.dta = one.dta
                  or b.dta = one.dta_b
    where   one.dta is null
  ')

dplyr::bind_rows(one, two)
#   dta id1 id2 id3 dta_b
# 1 FOO abc     def   FUU
# 2 BAR         fgh  <NA>
# 3 GOO bcd xyz       PAR
# 4 KOO     zzz      <NA>
1 голос
/ 10 октября 2019

По сути, вы хотите объединить с помощью соответствующих идентификаторов, что вы можете сделать, чтобы преобразовать исходные столбцы идентификаторов в id_column и id_value, потому что вы не хотите соединяться с "",упал.

library(tidyverse)
df_A_long <- df_A %>%
    pivot_longer(
        cols = -dta,
        names_to = "id_column",
        values_to = "id_value"
    ) %>%
    dplyr::filter(id_value != "")


df_B_long <- df_B %>%
    pivot_longer(
        cols = -dta,
        names_to = "id_column",
        values_to = "id_value"
    ) %>%
    dplyr::filter(id_value != "")

Мы всегда используем id_column и id_value, чтобы присоединиться к A & B.

> df_B_long
# A tibble: 3 x 3
  dta   id_column id_value
  <chr> <chr>     <chr>   
1 FUU   id1       abc     
2 PAR   id2       xyz     
3 KOO   id2       zzz 

Присоединяемая часть понятна, но для создания желаемого результата,нам нужно немного обработать данные, чтобы они выглядели одинаково.

df_joined <- df_A_long %>%
    # join using id_column and id_value
    full_join(df_B_long, by = c("id_column","id_value"),suffix = c("1","2")) %>%
    # pivot back to long format
    pivot_wider(
        id_cols = c(dta1,dta2),
        names_from = id_column,
        values_from = id_value
    ) %>%
    # if dta1 is missing, then in the same row, move value from dta2 to dta1
    mutate(
        dta1_has_value = !is.na(dta1), # helper column
        dta1 = ifelse(dta1_has_value,dta1,dta2),
        dta2 = ifelse(!dta1_has_value & !is.na(dta2),NA,dta2)
    ) %>%
    select(-dta1_has_value) %>%
    group_by(dta1) %>%
    # condense multiple rows into one row
    summarise_all(
        ~ifelse(all(is.na(.x)),"",.x[!is.na(.x)])
    ) %>%
    # reorder columns
    {
        .[sort(colnames(df_joined))]
    }

Результат:

> df_joined
# A tibble: 4 x 5
  dta1  dta2  id1   id2   id3  
  <chr> <chr> <chr> <chr> <chr>
1 BAR   ""    ""    ""    fgh  
2 FOO   FUU   abc   ""    def  
3 GOO   PAR   bcd   xyz   ""   
4 KOO   ""    ""    zzz   ""   
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...