在R中匹配文本字符串时如何处理拼写错误

13

我正在收集调查数据(使用开放数据工具包),我的野外团队有时会在人名拼写上稍微有些创意。因此,我有一个“正确”的受访者姓名,以及一些记录与“家庭成员姓名”变量相关联的年龄变量。有许多不同年龄的家庭成员。我想知道受访者的年龄。

以下是一些虚假数据,说明了我的问题:

#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个家庭成员。我已经改变了调查方式来分别记录受访者的年龄,但我需要清理一堆数据。


2
你看过Google Refine吗?http://code.google.com/p/google-refine/ - Ben Bolker
2个回答

20
拼写问题通常使用soundex算法的某个变体来处理。 RecordLinkage软件包中有一个R实现。然后,您需要比较的不是字符串本身,而是它们的“音标编码”:
> soundex('Clenton') == soundex('Clinton')
[1] TRUE

更新: 还有另一种确定两个单词是否“接近”的方法-即这些单词之间的某种“距离”。距离的一个标准度量是将第一个单词转换为第二个单词所需的最小字母替换、删除和插入的数量。它被称为Levenshtein distance。RecordLinkage和vwr包都有适当的函数:

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

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

然后您可以使用距离,并且如果距离不超过某个阈值,则认为单词足够“接近”。
更新:phonics包中也提供了soundex

2
两个都很好的答案:我将接受那个声望较低的人所给出的答案。 - generic_user
RecordLinkage在R中不再可用。有什么替代方案吗? - Alexis

18

我建议您使用Jaro-Winkler距离,这是一种字符串相似度度量,专门用于解决美国人口普查数据中的此类问题。它比莱文斯坦距离更为复杂,并专门设计用于处理姓名。您可以在RecordLinkage软件包中找到R实现。您需要设置一个阈值(例如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)但低于高阈值的记录发送至人工审核。您应该尝试调整这些数字,看看哪种方法适合您。这些值将决定您的灵敏度/特异性权衡


2
两个都是很好的答案:我会接受那个声望较低的人的答案。 - generic_user

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接