Заменить строку на наиболее частое нечеткое совпадение - PullRequest
2 голосов
/ 05 февраля 2020

У меня есть фрейм данных неструктурированных имен, и я хочу создать «основной» список очищенного имени в одном столбце со всеми вариантами в другом столбце. Я использую пакет stringdist. Ниже приведен небольшой пример:

library(dplyr) # for pipes 
library(tidyr) # for expand_grid()
library(stringdist) 

words <- c("dog","dot","don","con","cry","croak","cat","dogg", "dogy", "dog", "cat", "dog")
# compare everything to everything 
words_df <- expand_grid(raw = words, clean = words) %>%
    mutate(dist = stringdist(raw, clean, method = "jw") %>% 
    # compute word frequency 
    group_by(clean) %>%
    mutate(count = n()) %>%
filter(dist < 0.3) 

Это приводит к df с расстоянием и количеством слов для всех достаточно похожих комбинаций:

|raw |clean |      dist| count|
|:---|:-----|---------:|-----:|
|dog |dog   | 0.0000000|    36|
|dog |dot   | 0.2222222|    12|
|dog |don   | 0.2222222|    12|
|dog |dogg  | 0.0833333|    12|
|dog |dogy  | 0.0833333|    12|
|dog |dog   | 0.0000000|    36|
|dog |dog   | 0.0000000|    36|
|dot |dog   | 0.2222222|    36|
|dot |dot   | 0.0000000|    12|
|dot |don   | 0.2222222|    12|

Вы можете видеть это в clean У меня есть две записи для "собаки" и "собаки", которые я хотел бы свернуть в одну запись (собаку), потому что строка "собака" появляется чаще.

Вот что я пробовал до сих пор:

dict <- words_df %>%
    mutate(clean_new = ifelse(dist < 0.085, words_df[which.max(words_df$count)][[1]][1], clean))    

Что приводит к:

|raw |clean |      dist| count|clean_new |
|:---|:-----|---------:|-----:|:---------|
|dog |dog   | 0.0000000|    36|NA        |
|dog |dot   | 0.2222222|    12|dot       |
|dog |don   | 0.2222222|    12|don       |
|dog |con   | 0.4444444|    12|con       |
|dog |cry   | 1.0000000|    12|cry       |
|dog |croak | 0.4888889|    12|croak     |
|dog |cat   | 1.0000000|    24|cat       |
|dog |dogg  | 0.0833333|    12|NA        |
|dog |dogy  | 0.0833333|    12|NA        |
|dog |dog   | 0.0000000|    36|NA        |

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

Спасибо всем!

1 Ответ

2 голосов
/ 05 февраля 2020

Этот оператор dplyr pipe возвращает фрейм данных с 9 строками, по одной на каждый из уникальных элементов в вашем исходном векторе words. Сначала мы group_by столбец raw, который создает группу для каждого уникального слова, затем filter по вашему пороговому расстоянию, затем находим соответствующее слово в clean с самой высокой частотой в исходном наборе данных. В вашем примере все слова совпадают, за исключением двух вариантов слова "собака".

Код

words_df %>%
  group_by(raw) %>%
  filter(dist < 0.085) %>%
  summarize(clean = clean[which.max(count)])

Вывод

# A tibble: 9 x 2
  raw   clean
  <chr> <chr>
1 cat   cat  
2 con   con  
3 croak croak
4 cry   cry  
5 dog   dog  
6 dogg  dog  
7 dogy  dog  
8 don   don  
9 dot   dot  
...