Соединение двух таблиц путем перекрестной проверки двух по двум столбцам в R tidyverse - PullRequest
0 голосов
/ 31 января 2019

Вопрос:

Как эффективно объединить две таблицы путем перекрестной проверки столбцов 2x2 с использованием R tidyverse и dplyr?Я относительно новичок в R, но я не могу найти этот вопрос в предыдущих вопросах или обсуждениях.

У меня есть две таблицы с разным количеством строк и столбцов.Каждая таблица содержит столбцы A и B. Эти столбцы содержат строки, которые могут быть одинаковыми или уникальными, а также могут перекрываться или отсутствовать в одном или другом столбце.По сути, мне нужно проверить столбец A1 в отношении A2 и B2, а затем проверить B1 в отношении A2 и B2.

Пример для объяснения концепции:

df1
ID          pISSN       eISSN       Level
437097                  1530-9932   1
489309      2366-004X   2366-0058   1
437103      0025-5858               1
437109      1042-9670   1545-7230   1
449363      1093-1139               0
437127                  0949-1775   1
437124      0361-3682   1873-6289   2
481203      0103-846X   0103-846X   1
479825      2153-2184   2153-2192   0
437136      0734-2071   1557-7333   2


df2
ID          pISSN       eISSN       Format
41120                   2364-9534   E OA S C
12249                   1530-9932   E OF S
261                     2366-0058   E OF S
12188       0025-5858   1865-8784   PE OF S
40596       1042-9670   1545-7230   PE OF S
12129       0895-4852   1936-4709   PE OF
769         0949-1775   1432-0517   PE OF S


result
ID          pISSN       eISSN       Level   Format
437097                  1530-9932   1       E OF S
489309      2366-004X   2366-0058   1       E OF S
437103      0025-5858   1865-8784   1       PE OF S
437109      1042-9670   1545-7230   1       PE OF S
437127                  0949-1775   1       PE OF S

Примеры таблиц для ввода:

dput(df1, file = "")
structure(list(ID = c(437097, 489309, 437103, 437109, 449363, 437127, 437124, 481203, 479825, 437136), pISSN = c(NA, "2366-004X", "0025-5858", "1042-9670", "1093-1139", NA, "0361-3682", "0103-846X", "2153-2184", "0734-2071"), eISSN = c("1530-9932", "2366-0058", NA, "1545-7230", NA, "0949-1775", "1873-6289", "0103-846X", "2153-2192", "1557-7333"), Level = c(1, 1, 1, 1, 0, 1, 2, 1, 0, 2)), row.names = c(NA, -10L), class = c("tbl_df", "tbl", "data.frame"))

dput(df2, file = "")
structure(list(ID = c(41120, 12249, 261, 12188, 40596, 12129, 769), pISSN = c(NA, NA, NA, "0025-5858", "1042-9670", "0895-4852", "0949-1775"), eISSN = c("2364-9534", "1530-9932", "2366-0058", "1865-8784", "1545-7230", "1936-4709", "1432-0517"), Format = c("E OA S C", "E OF S", "E OF S", "PE OF S", "PE OF S", "PE OF", "PE OF S")), row.names = c(NA, -7L), class = c("tbl_df", "tbl", "data.frame"))

Ответы [ 2 ]

0 голосов
/ 06 февраля 2019

Кажется, теперь я понимаю, чего вы пытаетесь достичь.

Код

# Step 1
library(magrittr)
suppressMessages(library(dplyr))
library(fuzzyjoin)

# Step 2
df1 <- structure(list(ID = c(437097, 489309, 437103, 437109, 449363, 437127, 437124, 481203, 479825, 437136), pISSN = c(NA, "2366-004X", "0025-5858", "1042-9670", "1093-1139", NA, "0361-3682", "0103-846X", "2153-2184", "0734-2071"), eISSN = c("1530-9932", "2366-0058", NA, "1545-7230", NA, "0949-1775", "1873-6289", "0103-846X", "2153-2192", "1557-7333"), Level = c(1, 1, 1, 1, 0, 1, 2, 1, 0, 2)), row.names = c(NA, -10L), class = c("tbl_df", "tbl", "data.frame"))
df2 <- structure(list(ID = c(41120, 12249, 261, 12188, 40596, 12129, 769), pISSN = c(NA, NA, NA, "0025-5858", "1042-9670", "0895-4852", "0949-1775"), eISSN = c("2364-9534", "1530-9932", "2366-0058", "1865-8784", "1545-7230", "1936-4709", "1432-0517"), Format = c("E OA S C", "E OF S", "E OF S", "PE OF S", "PE OF S", "PE OF", "PE OF S")), row.names = c(NA, -7L), class = c("tbl_df", "tbl", "data.frame"))

# Step 3  
my_match <- function(key1, key2) {
  match <- key1 == key2
  match[is.na(match)] <- FALSE
  return(match)
}

# Step 4 
bind_rows(
fuzzy_inner_join(df1, df2, 
                 by = c("pISSN" = "pISSN"), 
                 match_fun = list(my_match)),
fuzzy_inner_join(df1, df2, 
                 by = c("eISSN" = "pISSN"), 
                 match_fun = list(my_match)),
fuzzy_inner_join(df1, df2, 
                 by = c("pISSN" = "eISSN"), 
                 match_fun = list(my_match)),
fuzzy_inner_join(df1, df2, 
                 by = c("eISSN" = "eISSN"), 
                 match_fun = list(my_match))
) %>% # Step 5
  mutate(pISSN = coalesce(pISSN.x, pISSN.y),
         eISSN = coalesce(eISSN.x, eISSN.y)) %>%
  select(-c("pISSN.x", "pISSN.y", "eISSN.x", "eISSN.y")) %>%
  select("ID.x", "ID.y", "pISSN", "eISSN", "Level", "Format") -> result

result
#> # A tibble: 6 x 6
#>     ID.x  ID.y pISSN     eISSN     Level Format 
#>    <dbl> <dbl> <chr>     <chr>     <dbl> <chr>  
#> 1 437103 12188 0025-5858 1865-8784     1 PE OF S
#> 2 437109 40596 1042-9670 1545-7230     1 PE OF S
#> 3 437127   769 0949-1775 0949-1775     1 PE OF S
#> 4 437097 12249 <NA>      1530-9932     1 E OF S 
#> 5 489309   261 2366-004X 2366-0058     1 E OF S 
#> 6 437109 40596 1042-9670 1545-7230     1 PE OF S

Объяснение каждого шага

  1. Я загружаю некоторые необходимые пакеты,а именно: magrittr, для трубного оператора %>%;dplyr, для bind_rows (аналог rbind), mutate и selectfuzzyjoin для fuzzy_inner_join.
  2. Затем я создаю два примера фреймов данных: df1 и df2.
  3. Мы определяем функцию my_match.Эта функция выполняет сопоставление на основе равенства, но когда задействовано NA s, она возвращает FALSE (без совпадения) вместо NA.
  4. Затем мы используем fuzzy_inner_join, чтобы выполнить четыре соединения следующим образомклавиши: (i) df1 "pISSN" и df2 "pISSN";(ii) df1 "eISSN" и df2 "pISSN";(iii) df1 "pISSN" и df2 "eISSN";и (iv) df1 "eISSN" и df2 "eISSN".Это та часть, где мы делаем то, что вы назвали перекрестной проверкой столбцов 2x2 .Затем мы обертываем эти четыре результирующих фрейма данных в bind_rows, чтобы все эти наблюдения (строки) были объединены в один фрейм данных.
  5. Наконец, мы проводим некоторую обработку данных, чтобы получить фрейм данных в нужной форме: (i) мы используем mutate для создания двух новых столбцов pISSN и eISSN из столбцов pISSN.x (первоначально df1) и pISSN.y (первоначально df2) и eISSN.x (изdf1) и eISSN.y (из df2) соответственно;(ii) и мы используем select для хранения / удаления столбцов.

Примечание: в отличие от вашего предполагаемого result, я вывожу два ID столбца, один из df1 идругой от df2.В своем посте вы держали только ID из фрейма данных df1.Но однозначно, какой из них оставить, поэтому я оставил два.Вы всегда можете отказаться от одного из них с помощью select(-ID.x) или select(-ID.y).

0 голосов
/ 01 февраля 2019

Я немного смущен вашим примером кода, а затем кодом, которым вы поделились с dput, потому что я не уверен, как они связаны ... но вот мое мнение по вашему вопросу:

library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
library(stringr)

df1 <- structure(list(ID = c(437097, 489309, 437103, 437109, 449363, 437127, 437124, 481203, 479825, 437136), pISSN = c(NA, "2366-004X", "0025-5858", "1042-9670", "1093-1139", NA, "0361-3682", "0103-846X", "2153-2184", "0734-2071"), eISSN = c("1530-9932", "2366-0058", NA, "1545-7230", NA, "0949-1775", "1873-6289", "0103-846X", "2153-2192", "1557-7333"), Level = c(1, 1, 1, 1, 0, 1, 2, 1, 0, 2)), row.names = c(NA, -10L), class = c("tbl_df", "tbl", "data.frame"))


df2 <- structure(list(ID = c(41120, 12249, 261, 12188, 40596, 12129, 769), pISSN = c(NA, NA, NA, "0025-5858", "1042-9670", "0895-4852", "0949-1775"), eISSN = c("2364-9534", "1530-9932", "2366-0058", "1865-8784", "1545-7230", "1936-4709", "1432-0517"), Format = c("E OA S C", "E OF S", "E OF S", "PE OF S", "PE OF S", "PE OF", "PE OF S")), row.names = c(NA, -7L), class = c("tbl_df", "tbl", "data.frame"))

surrogate_key <- Vectorize(function(x, y) {
  str_c(sort(c(x, y)), collapse = "")
})

df1 %>% mutate(join_key = surrogate_key(pISSN, eISSN)) -> df3
df2 %>% mutate(join_key = surrogate_key(pISSN, eISSN)) -> df4

result <- full_join(df3, df4, "join_key") %>%
  select(-join_key)
#> Warning: Column `join_key` has different attributes on LHS and RHS of join

result
#> # A tibble: 15 x 8
#>      ID.x pISSN.x   eISSN.x   Level  ID.y pISSN.y   eISSN.y   Format  
#>     <dbl> <chr>     <chr>     <dbl> <dbl> <chr>     <chr>     <chr>   
#>  1 437097 <NA>      1530-9932     1 12249 <NA>      1530-9932 E OF S  
#>  2 489309 2366-004X 2366-0058     1    NA <NA>      <NA>      <NA>    
#>  3 437103 0025-5858 <NA>          1    NA <NA>      <NA>      <NA>    
#>  4 437109 1042-9670 1545-7230     1 40596 1042-9670 1545-7230 PE OF S 
#>  5 449363 1093-1139 <NA>          0    NA <NA>      <NA>      <NA>    
#>  6 437127 <NA>      0949-1775     1    NA <NA>      <NA>      <NA>    
#>  7 437124 0361-3682 1873-6289     2    NA <NA>      <NA>      <NA>    
#>  8 481203 0103-846X 0103-846X     1    NA <NA>      <NA>      <NA>    
#>  9 479825 2153-2184 2153-2192     0    NA <NA>      <NA>      <NA>    
#> 10 437136 0734-2071 1557-7333     2    NA <NA>      <NA>      <NA>    
#> 11     NA <NA>      <NA>         NA 41120 <NA>      2364-9534 E OA S C
#> 12     NA <NA>      <NA>         NA   261 <NA>      2366-0058 E OF S  
#> 13     NA <NA>      <NA>         NA 12188 0025-5858 1865-8784 PE OF S 
#> 14     NA <NA>      <NA>         NA 12129 0895-4852 1936-4709 PE OF   
#> 15     NA <NA>      <NA>         NA   769 0949-1775 1432-0517 PE OF S
...