Работа с неправильным написанием при сопоставлении текстовых строк в R

Я собираю данные опроса (используя комплект открытых данных), и моя полевая группа, благослови их сердца, иногда проявляет некоторую изобретательность в написании имен людей. Итак, у меня есть «правильное» имя респондента, а также переменная возраста для некоторых записей, которая связана с переменной «имя члена семьи». В семье много разновозрастных членов семьи. Мне нужен возраст респондента.

Вот некоторые поддельные данные, которые иллюстрируют мою проблему:

#the respondent
    r = data.frame(name = c("Barack Obama", "George Bush", "Hillary Clinton"))
#a male member
    m = data.frame(name = c("Barack Obama","George", "Wulliam Clenton"), age = c(55,59,70)); m$name=as.character(m$name)
#a female member
    f = data.frame(name = c("Michelle O","Laura Busch", "Hillary Rodham Clinton"), age = c(54,58,69)); f$name=as.character(f$name)
#if the responsent is the the given member, record their age.  if not, NA
    a = cbind(
        ifelse(r$name==m$name,m$age,NA)
        ,ifelse(r$name==f$name,f$age,NA)
        )
    #make a function for plyr that gives me the age of the matched respondent
    f = function(row){
        d = row[is.na(row)==0]
        ifelse(length(d)==0,NA,d)
        }
    require(plyr)
    b = aaply(a,.margins=1,.fun=f)
    data.frame(names=r$name,age=b)
                names age
    1    Barack Obama  55
    2     George Bush  NA
    3 Hillary Clinton  NA

    what.I.would.like = data.frame(names=c("Barack Obama", "George Bush", "Hillary Clinton"),age = c(55,59,70))
    1> what.I.would.like
                names age
    1    Barack Obama  55
    2     George Bush  59
    3 Hillary Clinton  70

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


person generic_user    schedule 30.05.2013    source источник
comment
Вы смотрели на Google Refine code.google.com/p/google-refine? ?   -  person Ben Bolker    schedule 30.05.2013


Ответы (2)


Проблемы правописания обычно решаются с помощью некоторого варианта алгоритма soundex. В пакете RecordLinkage есть реализация R. Тогда нужно сравнивать не сами строки, а их «фонетические коды»:

> soundex('Clenton') == soundex('Clinton')
[1] TRUE

ОБНОВЛЕНИЕ: Существует также другой способ определить, являются ли два слова "близкими" друг к другу - это "расстояние" - это некоторый смысл между словами. Одной стандартной мерой расстояний является минимальное количество однобуквенных замен, удалений и вставок, необходимых для преобразования первого слова во второе. Это называется расстоянием Левенштейна. Пакет RecordLinkage, а также пакет vwr имеют соответствующие функции:

> levenshteinDist('Clinton', 'Clenton')
[1] 1

> vwr::levenshtein.distance('Clinton', 'Clenton')
Clenton 
  1 

Тогда можно использовать расстояния и считать слова «близко» достаточными, если расстояние не превышает некоторого порога.

ОБНОВЛЕНИЕ: soundexтакже доступен в пакете phonics.

person Alex Vorobiev    schedule 30.05.2013
comment
Оба отличных ответа: я приму ответ от человека с более низкой репутацией. - person generic_user; 31.05.2013
comment
RecordLinkage больше не доступен для R. Любые альтернативы? - person Alexis; 20.02.2020

Я рекомендую вам использовать расстояние Jaro-Winkler — показатель сходства строк, разработанный для решить эту точную проблему в данных переписи населения США. Оно более сложное, чем расстояние Левенштейна, и разработано специально для работы с именами. Вы можете найти реализацию R в пакете RecordLinkage. Вам нужно будет установить порог отсечения (например, 0,8) для того, насколько похожими должны быть две строки.

install.packages('RecordLinkage','RSQLite')
require(RecordLinkage)

jarowinkler('William Clinton', "Willam Clntn")
# 0.96
jarowinkler('William Clinton', "Wuliam Clinton")
# 0.8462637
jarowinkler('William Clinton', "Hilary Clinton")
# 0.7790765

Я бы рекомендовал установить достаточно высокий порог (возможно, 0,9) для автоматического сопоставления, а затем отправлять записи ниже высокого порога, но выше вторичного нижнего порога (возможно, 0,7) для проверки человеком. Вы должны поиграть с этими числами и посмотреть, что работает для вас. Эти значения будут определять ваш компромисс между чувствительностью и специфичностью.

person David Marx    schedule 30.05.2013
comment
Оба отличных ответа: я приму ответ от человека с более низкой репутацией. - person generic_user; 31.05.2013