2016-10-07 2 views
0

У меня есть два dataframes, с двумя символьными векторами различной длины, которые я хотел бы, чтобы соответствовать, например, так:Подмножество с использованием grep для включения levenshtein distance?

company.a <- c("heinz", "hawkings mcgill", "heinz ketchup", "heinz vinegars", "davis and smith", "dell computers", "dell", "O organics", "organics") 

company.b <- c("heinz", "hawkings-mcgill", "oyster bay", "company x", "dell") 

Я хотел бы сравнить company.b к company.a, возвращая вектор, содержащий элемент от company.b, который был сопоставлен с company.a. Я попытался с помощью следующего кода для подмножества тем больше фрейм

match.comp <- subset(company.a, grep(paste(company.b, collapse = "|"), company.a, value = TRUE)). 

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

match <- c("heinz", "hawkings mcgill", "heinz", "heinz", "FALSE", "dell", "dell", FALSE, FALSE) 

Учитывая ошибки, очевидно, я что-то о Grep или подмножестве отсутствует. У меня есть два вопроса:

  1. Является ли grep лучшим способом для этого? Или есть другой способ? Я знаю о точном сопоставлении, используя подход (A% in% B), но я не могу гарантировать, что строки будут точными совпадениями.

  2. Grep вернет первое совпадение, но есть ли способ извлечь все возможные совпадения, которые были рассмотрены через, скажем, расстояние levenshtein? Я знаю функцию adist в пакете utils, но я хочу знать, можно ли комбинировать ее с grep.

Любая помощь или совет были бы очень признательны. Благодарю.

+0

'agrep'? Ваш желаемый результат неясен. – alistaire

+0

@alistaire спасибо. agrep выглядит хорошо. я хочу вернуть согласованные элементы, если они работают, а если нет, логическое значение. это яснее? – jvalenti

ответ

1

Вы можете использовать adist или agrep, но это очень субъективный процесс с точки зрения затрат и точек отсечения. В этом случае вы можете получить желаемый результат с помощью

d <- adist(company.b, company.a, partial = TRUE) 
d <- apply(d, 2, prop.table) # working with proportions instead of costs can be useful 

matches <- apply(d, 2, function(x){ 
    x <- setNames(x, company.b) 
    names(which.min(x[x < 0.05])) # set cutoff carefully 
}) 
matches <- sapply(matches, function(x){ifelse(is.null(x), NA, x)}) # clean out NULLs 

matches 
## [1] "heinz"   "hawkings-mcgill" "heinz"   "heinz"   NA    
## [6] "dell"   "dell"   NA    NA  
+0

спасибо, что это действительно отличное решение! Я очень ценю помощь. есть ли у вас какие-либо рекомендации по процедурам определения оптимальных точек отсечки для очень больших кадров данных? или, по крайней мере, где я могу посмотреть, чтобы понять это? еще раз спасибо. – jvalenti

+1

Это немного зависит от того, что вы знаете о струнах и о том, с чем вы хотите, чтобы они соответствовали. Учитывая приведенный выше пример, строки для сопоставления были в основном короче, поэтому я использовал 'partial = TRUE', который соответствует подстрокам без стоимости удаления символов, но вы можете явно установить стоимость удаления. Прочитайте документы и поиграйте, но по слишком большим объемам, чтобы проверять вручную, я бы проверял количество ошибок на подмножестве, которое вы проверяете вручную, сродни ошибкам обучения в построении модели. – alistaire

+0

Вы можете объяснить немного больше об отключении? Соответствует ли это тем, у кого доля одинаковых символов меньше 5%? – jvalenti

2

Это может частично удовлетворить ваши требования:

library(utils) 

company.a <- c("heinz", "hawkings mcgill", "heinz ketchup", "heinz vinegars", "davis and smith", "dell computers", "dell", "O organics", "organics") 
company.b <- c("heinz", "hawkings-mcgill", "oyster bay", "company x", "dell") 

limit <- 2 

res <- sapply(company.a, function(wa) { 
    d <- sapply(company.b, function(wb){ 
     adist(wb, wa) 
    }) 
    d <- d[d<=limit] 
    names(d) 
}) 

выше фрагмент кода будет извлекать все матчи во втором массиве, каждое слово в первом массиве. Здесь два слова сопоставляются, если расстояние Левенштейна является максимальным «пределом».

Также обратите внимание, что некоторые из совпадений, которые вы указали выше, не так просты. Например, если «heinz» должен соответствовать «heinz ketchup», для этого потребуется предел расстояния Levenshtein в 8, который будет слишком высоким в целом. Чтобы справиться с этими случаями, должна быть построена более активная функция расстояния.

Смежные вопросы