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 个家庭成员。从那以后,我将调查更改为分别记录受访者的年龄,但我有一堆数据需要清理。

4

2 回答 2

20

拼写问题通常使用soundex算法的一些变体来处理。RecordLinkage包中有一个 R 实现。然后你需要比较的不是字符串本身,而是它们的“语音代码”:

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

更新:还有另一种方法可以确定两个词是否彼此“接近” - 这是“距离”是词之间的某种意义。距离的一个标准度量是将第一个单词转换为第二个单词所需的单个字母替换、删除和插入的最小量。它被称为Levenshtein 距离。RecordLinkage 以及vwr包具有相应的功能:

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

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

然后,如果距离不超过某个阈值,您可以使用距离并考虑“接近”这个词。

更新: soundex也可在语音包中使用。

于 2013-05-30T14:27:01.623 回答
18

我建议您使用Jaro-Winkler距离,这是一种字符串相似度度量,用于解决美国人口普查数据中的这个确切问题。它比 levenshtein distance 更复杂,专为处理名称而设计。您可以在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)的记录发送给人工审查。你应该玩这些数字,看看什么对你有用。这些值将决定您的敏感性/特异性权衡

于 2013-05-30T15:52:49.467 回答