通过模糊匹配名称创建唯一ID(通过使用R的agrep)
使用R,我尝试在按年份和城市构建的数据集中匹配人名。由于一些拼写错误,无法精确匹配,因此我尝试使用agrep()模糊匹配名称 数据集的样本块的结构如下所示:通过模糊匹配名称创建唯一ID(通过使用R的agrep),r,string-matching,fuzzy,agrep,R,String Matching,Fuzzy,Agrep,使用R,我尝试在按年份和城市构建的数据集中匹配人名。由于一些拼写错误,无法精确匹配,因此我尝试使用agrep()模糊匹配名称 数据集的样本块的结构如下所示: df <- data.frame(matrix( c("1200013","1200013","1200013","1200013","1200013","1200013","1200013",&
df <- data.frame(matrix( c("1200013","1200013","1200013","1200013","1200013","1200013","1200013","1200013", "1996","1996","1996","1996","2000","2000","2004","2004","AGUSTINHO FORTUNATO FILHO","ANTONIO PEREIRA NETO","FERNANDO JOSE DA COSTA","PAULO CEZAR FERREIRA DE ARAUJO","PAULO CESAR FERREIRA DE ARAUJO","SEBASTIAO BOCALOM RODRIGUES","JOAO DE ALMEIDA","PAULO CESAR FERREIRA DE ARAUJO"), ncol=3,dimnames=list(seq(1:8),c("citycode","year","candidate")) ))
我想分别在每个城市登记,几年后是否有候选人出现。例如,在示例中
保罗·塞扎·费雷拉·德阿劳乔
保罗·塞萨尔·费雷拉·德阿劳乔
出现两次(有拼写错误)。整个数据集中的每个候选对象都应分配一个唯一的数字候选ID。数据集相当大(5500个城市,约100K个条目),因此某种程度上高效的编码可能会有所帮助。有没有关于如何实施的建议
编辑:以下是我的尝试(在目前评论的帮助下),它在完成手头的任务方面非常缓慢(低效)。对此有何改进建议
f <- function(x) {matches <- lapply(levels(x), agrep, x=levels(x),fixed=TRUE, value=FALSE)
levels(x) <- levels(x)[unlist(lapply(matches, function(x) x[1]))]
x
}
temp <- tapply(df$candidate, df$citycode, f, simplify=TRUE)
df$candidatenew <- unlist(temp)
df$spellerror <- ifelse(as.character(df$candidate)==as.character(df$candidatenew), 0, 1)
f这是我的尝试。这可能不是很有效,但我认为它会完成工作。我假设df$candidates
是类因素
#fuzzy matches candidate names to other candidate names
#compares each pair of names only once
##by looking at names that have a greater index
matches <- unlist(lapply(1:(length(levels(df[["candidate"]]))-1),
function(x) {max(x,x + agrep(
pattern=levels(df[["candidate"]])[x],
x=levels(df[["candidate"]])[-seq_len(x)]
))}
))
#assigns new levels (omits the last level because that doesn't change)
levels(df[["candidate"]])[-length(levels(df[["candidate"]]))] <-
levels(df[["candidate"]])[matches]
#fuzzy将候选名称与其他候选名称进行匹配
#仅对每对名称进行一次比较
##通过查看索引较大的名称
匹配好的,考虑到重点是效率,我建议如下
首先,请注意,根据第一原理的效率顺序,我们可以预测精确匹配将比grep快得多,grep将比模糊grep快得多。所以精确匹配,然后对剩余的观测值进行模糊grep
第二,矢量化和避免循环。apply
命令并不一定更快,因此如果可以,请坚持使用本机矢量化。所有的grep
命令都是本机矢量化的,但是很难避免使用*ply
或循环将每个元素与其他元素的矢量进行比较
第三,利用外部信息缩小问题范围。例如,只对每个城市或州的名字进行模糊匹配,这将大大减少必须进行的比较
您可以结合第一和第三原则:您甚至可以尝试对每个字符串的第一个字符进行精确匹配,然后在其中进行模糊匹配。到目前为止您尝试了什么?让agrep与之匹配或有效地进行匹配有问题吗?主要是效率方面的问题。我在所有城市和候选人中进行了一次循环,但这需要相当长的时间。我能够在每个城市中找到模糊匹配,但很难在整个数据集中创建唯一的ID。你能为你的循环发布代码吗?另请参见.My循环是| | for(i in 1:dim(df)[1]){df$match[i]=sort(agrep(df$candidate[i],df$candidate,ignore.case=FALSE,value=TRUE,max.distance=0.1))[1]}df$candid第一部分很棒。第二部分似乎没有运行。无论如何,谢谢你让我开始。也许你有一个关于如何改进我添加到问题中的“解决方案”的建议。我已经更新了一些我认为更好的东西。您不必通过尽可能多的元素执行agreep
。它在样本数据集上工作,但我“我不确定它在更大的数据集上的效果如何。非常感谢。与许多层次的比较确实是个问题。现在,我将比较限制在每个组内的级别,速度快了数百倍。如果您允许,最后一个问题是关于您以前的解决方案。我可以在行中为agrep命令添加一些选项吗:lappy(levels(x),agrep,x=levels(x),fixed=TRUE,value=FALSE)我想指定“max.distance”。是:lappy(levels(x),agrep,x=levels(x),fixed=TRUE,value=FALSE,max.distance=.2)
。(注意,您可以使用反引号`
将文本格式化为代码)
df$candidate <- as.character(df$candidate)
f <- function(x) {x <- as.factor(x)
matches <- lapply(levels(x), agrep, x=levels(x),fixed=TRUE, value=FALSE)
levels(x) <- levels(x)[unlist(lapply(matches, function(x) x[1]))]
as.character(x)
}
temp <- tapply(df$candidate, df$citycode, f, simplify=TRUE)
df$candidatenew <- unlist(temp)
df$spellerror <- ifelse(as.character(df$candidate)==as.character(df$candidatenew), 0, 1)
#fuzzy matches candidate names to other candidate names
#compares each pair of names only once
##by looking at names that have a greater index
matches <- unlist(lapply(1:(length(levels(df[["candidate"]]))-1),
function(x) {max(x,x + agrep(
pattern=levels(df[["candidate"]])[x],
x=levels(df[["candidate"]])[-seq_len(x)]
))}
))
#assigns new levels (omits the last level because that doesn't change)
levels(df[["candidate"]])[-length(levels(df[["candidate"]]))] <-
levels(df[["candidate"]])[matches]