Соединение фреймов данных на основе нечеткого сопоставления строк - PullRequest
1 голос
/ 02 апреля 2020
library(tidyverse)
library(fuzzyjoin)
df1 <- tibble(col1 = c("Apple Shipping", "Banana Shipping", "FedEX USA Ground",
                       "FedEx USA Commercial", "FedEx International"),
              col2 = 1:5)
#> # A tibble: 5 x 2
#>   col1                  col2
#>   <chr>                <int>
#> 1 Apple Shipping           1
#> 2 Banana Shipping          2
#> 3 FedEX USA Ground         3
#> 4 FedEx USA Commercial     4
#> 5 FedEx International      5

df2 <- tibble(col3 = c("Banana", "FedEX USA"), col4 = c(700, 900))
#> # A tibble: 2 x 2
#>   col3       col4
#>   <chr>     <dbl>
#> 1 Banana      700
#> 2 FedEX USA   900

Два фрейма данных, с которыми я работаю, показаны выше. Я хотел бы присоединиться к ним на col1 и col3, чтобы придумать нечто похожее на то, что прямо показано ниже. По существу, правило будет следующим: « Если весь текст в col3 находится в любом из col1, то считается, что это соответствует ».

#> # A tibble: 3 x 4
#>   col1                  col2  col3      col4
#>   <chr>                <int>  <chr>    <int>
#> 1 Banana Shipping          2  Banana     700
#> 2 FedEX USA Ground         3  FedEx USA  900
#> 3 FedEx USA Commercial     4  FedEx USA  900

Это более старое SO Похоже, вопрос предлагает решение , но в данном случае оно не совсем работает, и я получаю ошибки, показанные ниже:

df1 %>% regex_inner_join(df2, by = c(string = "col3"))
#> Error: All columns in a tibble must be 1d or 2d objects:
#> * Column `col` is NULL
#> Run `rlang::last_error()` to see where the error occurred.

library(stringr)
df1 %>% fuzzy_inner_join(df2, by = c("string" = "col3"), match_fun = str_detect)
#> Error: All columns in a tibble must be 1d or 2d objects:
#> * Column `col` is NULL
#> Run `rlang::last_error()` to see where the error occurred.

Как выполнить нечеткое соединение с R?

1 Ответ

3 голосов
/ 02 апреля 2020

Возможно, это то, что вы ищете?

library(dplyr)
library(fuzzyjoin)
library(stringr)
df1 %>% fuzzy_inner_join(df2,by=c("col1" = "col3"),match_fun = str_detect)
## A tibble: 2 x 4
#  col1              col2 col3       col4
#  <chr>            <int> <chr>     <dbl>
#1 Banana Shipping      2 Banana      700
#2 FedEX USA Ground     3 FedEX USA   900

Если вы хотите игнорировать регистр, вы можете определить свой собственный str_detect.

my_str_detect <- function(x,y){str_detect(x,regex(y, ignore_case = TRUE))}
df1 %>% fuzzy_inner_join(df2,by=c("col1" = "col3"),match_fun = my_str_detect)
## A tibble: 3 x 4
#  col1                  col2 col3       col4
#  <chr>                <int> <chr>     <dbl>
#1 Banana Shipping          2 Banana      700
#2 FedEX USA Ground         3 FedEX USA   900
#3 FedEx USA Commercial     4 FedEX USA   900

Для бонусных баллов Вы можете использовать agrepl из этого вопроса .

Вы можете изменить аргумент max.distance = и потенциально добавить cost =. Подробнее см. help(agrepl).

my_match_fun <- Vectorize(function(x,y) agrepl(x, y, ignore.case=TRUE, max.distance = 0.7, useBytes = TRUE))
df1 %>% fuzzy_inner_join(df2,by=c("col1" = "col3"),match_fun = my_match_fun)
## A tibble: 4 x 4
#  col1                  col2 col3       col4
#  <chr>                <int> <chr>     <dbl>
#1 Banana Shipping          2 Banana      700
#2 FedEX USA Ground         3 FedEX USA   900
#3 FedEx USA Commercial     4 FedEX USA   900
#4 FedEx International      5 FedEX USA   900
...