Объединение сгруппированных пар в одну группу в R - PullRequest
1 голос
/ 19 октября 2019

Я делаю большую задачу нечеткого соответствия в R, сопоставляя похожие имена магазинов друг с другом. В некоторых случаях есть несколько записей, связанных с одним хранилищем, и это привело к парам, где A = B, B = C и A = C. Я хотел бы объединить их в один идентификатор группы, чтобы онивсе могут быть объединены вместе. См. Эту таблицу ниже:

PairID   Store name
1        Quick Stop
2        TD's Food Shop
2        TD's Food Shops
3        TD's Food Shops
3        TD's Food Shop 1
4        TD's Food Shop
4        TD's Food Shop 1

Используя R / tidyverse, я не могу найти способ объединить PairID для 2, 3 и 4 в этом примере в одну группу. Другие нашли способ сделать это?

### EDIT

Похоже, что пакет refinr в R делает это довольно легко (https://github.com/ChrisMuir/refinr). Это автоматизированная реализация OpenRefine, которая для> 100 000 записей - то, что мне нужно - не надоиметь возможность сопоставления вручную. Код будет выглядеть примерно так:

df<-as_tibble(c("QuikStop","TJ's Foods","TJs Foods","TJ's Food"))
df$match<-n_gram_merge(df$value)

Результат будет выглядеть так:

value           match
QuikStop        QuikStop
TJ's Foods      TJ's Food
TJs Foods       TJ's Food
TJ's Food       TJ's Food

Веса для сопоставления можно настроить с помощью параметров из stringdistСпасибо за совет от комментаторов!

1 Ответ

0 голосов
/ 19 октября 2019

На самом деле это может стать чрезвычайно трудной проблемой, если вы хотите или должны сгруппировать строки по одинаковым именам магазинов без экзогенного указания количества реальных магазинов или их официальных названий. Это связано с тем, что вы неизбежно столкнетесь с нечетко перекрывающимися кластерами и нарушениями транзитивности при любом заданном пороговом расстоянии или минимизации расстояния между строками. A будет ближе всего к B, B будет ближе к C, а C будет не ближе к A, и что тогда? A и B не могут быть одним и тем же магазином, в то время как C является тем же магазином, что и B, но не A!

Если вы можете указать вектор канонических названий магазинов, тогда я рекомендую следующее, которое просто находитканоническое имя магазина, которое ближе к названию в каждой строке и создает новый столбец из этих ближайших канонических имен. Затем вы можете сгруппировать по значениям этого нового столбца и свернуть идентификаторы хранилища в векторы, разделенные запятыми, или что-то еще.

library(future)
library(stringdist)
library(tidyverse)
library(magrittr)
#> 
#> Attaching package: 'magrittr'
#> The following object is masked from 'package:purrr':
#> 
#>     set_names
#> The following object is masked from 'package:tidyr':
#> 
#>     extract

data <- tribble(
  ~PairID, ~`Store name`,
  1,       "Quick Stop",
  2,       "TD's Food Shop",
  2,       "TD's Food Shops",
  3,       "TD's Food Shops",
  3,       "TD's Food Shop 1",
  4,       "TD's Food Shop",
  4,       "TD's Food Shop 1"
)

standard_names <- c("Quick Stop", "TD's Food Shop")

plan(multiprocess)

data %<>% mutate(
  closest_name = 
    stringdistmatrix(`Store name`, standard_names, method = "jw") %>% 
    apply(1, function(x) which(x == min(x))) %>% 
    extract(standard_names, .)
)

data
#> # A tibble: 7 x 3
#>   PairID `Store name`     closest_name  
#>    <dbl> <chr>            <chr>         
#> 1      1 Quick Stop       Quick Stop    
#> 2      2 TD's Food Shop   TD's Food Shop
#> 3      2 TD's Food Shops  TD's Food Shop
#> 4      3 TD's Food Shops  TD's Food Shop
#> 5      3 TD's Food Shop 1 TD's Food Shop
#> 6      4 TD's Food Shop   TD's Food Shop
#> 7      4 TD's Food Shop 1 TD's Food Shop

combined_pairIDs <- 
  data %>% 
  group_by(closest_name) %>% 
  summarize_at("PairID", ~ toString(order(unique(.x)))) %>% 
  ungroup()

combined_pairIDs
#> # A tibble: 2 x 2
#>   closest_name   PairID 
#>   <chr>          <chr>  
#> 1 Quick Stop     1      
#> 2 TD's Food Shop 1, 2, 3

Создано в 2019-10-19 с помощью пакета представить (v0.3.0)

Обратите внимание, что здесь есть вероятность ошибки, которую я намеренно оставляю. Что делать, если одна из строк имеет имя, которое одинаково близко к двум илибольше канонических имен? Он попытается извлечь более одного значения из standard_names, что недопустимо. Если такие связи случаются, вам нужно решить, как вы хотите их разорвать и что они могут указывать на характер данных.

...