【问题标题】:Create a unique ID by fuzzy matching of names (via agrep using R)通过名称的模糊匹配创建唯一 ID(通过使用 R 的 agrep)
【发布时间】:2012-10-21 16:31:00
【问题描述】:

使用 R,我正在尝试匹配按年份和城市构成的数据集中的人名。由于一些拼写错误,无法完全匹配,所以我尝试使用 agrep() 来模糊匹配名称。

数据集的一个样本块的结构如下:

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")) ))

简洁版:

  citycode year                      candidate
1  1200013 1996      AGUSTINHO FORTUNATO FILHO
2  1200013 1996           ANTONIO PEREIRA NETO
3  1200013 1996         FERNANDO JOSE DA COSTA
4  1200013 1996 PAULO CEZAR FERREIRA DE ARAUJO
5  1200013 2000 PAULO CESAR FERREIRA DE ARAUJO
6  1200013 2000    SEBASTIAO BOCALOM RODRIGUES
7  1200013 2004                JOAO DE ALMEIDA
8  1200013 2004 PAULO CESAR FERREIRA DE ARAUJO

我想分别检查每个城市,几年后是否有候选人出现。例如。在示例中,

保罗·塞扎尔·费雷拉·德·阿劳霍

保罗·塞萨尔·费雷拉·德·阿劳霍

出现两次(有拼写错误)。应为整个数据集中的每个候选人分配一个唯一的数字候选人 ID。数据集相当大(5500 个城市,大约 100K 条目),因此稍微有效的编码会有所帮助。关于如何实现这一点的任何建议?

编辑:这是我的尝试(到目前为止,在 cmets 的帮助下)完成手头的任务非常缓慢(效率低下)。对此有何改进建议?

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)

编辑 2:现在以良好的速度运行。问题是在每一步都与许多因素进行比较(感谢蓝魔导师指出这一点)。将比较减少到仅一组(即一个城市)中的候选人在 5 秒内运行 80,000 行命令 - 这是我可以接受的速度。

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)

【问题讨论】:

  • 到目前为止您尝试过什么?让agrep 匹配或有效地进行匹配有问题吗?
  • 主要是效率部分。我遍历了所有城市和候选人,但这需要很长时间。我能够在每个城市中找到模糊匹配,但很难在整个数据集中创建唯一 ID。
  • 你能贴出你的循环代码吗?另见stackoverflow.com/questions/2908822/…
  • 我的循环是 || 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

标签: r string-matching fuzzy agrep


【解决方案1】:

这是我的尝试。它可能不是很有效,但我认为它会完成工作。我假设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]

【讨论】:

  • 第一部分很棒。第二部分似乎没有运行。无论如何,谢谢你让我开始。也许您对如何改进我添加到问题中的“解决方案”有建议。
  • 我更新了一些我认为更好的东西。您不必通过尽可能多的元素agrep。它适用于示例数据集,但我不确定它在更大的数据集上的效果如何。
  • 非常感谢。与许多级别的比较确实是问题所在。现在,我将比较限制在每个组内的级别,速度快了数百倍。
  • 如果您允许,关于您之前的解决方案的最后一个问题。我可以在以下行中的 agrep 命令中添加一些选项: lapply(levels(x), agrep, x=levels(x),fixed=TRUE, value=FALSE) 我想指定“max.distance”。跨度>
  • 是的:lapply(levels(x), agrep, x=levels(x),fixed=TRUE, value=FALSE, max.distance = .2)。 (请注意,您可以将文本格式化为带有反引号 ` 的代码。)
【解决方案2】:

好的,鉴于重点是效率,我建议如下。

首先,请注意,按照第一原则的效率顺序,我们可以预测精确匹配将比 grep 快得多,而 grep 将比模糊 grep 快。所以完全匹配,然后对剩余的观察结果进行模糊 grep。

第二,矢量化并避免循环。 apply 命令不一定更快,所以如果可以的话,请坚持使用原生矢量化。所有grep 命令都是原生矢量化的,但很难避免*ply 或循环将每个元素与其他元素的矢量进行比较以匹配。

第三,利用外部信息缩小问题范围。仅对每个城市或州内的名称进行模糊匹配,例如,这将大大减少必须进行的比较次数。

您可以结合第一和​​第三个原则:您甚至可以尝试对每个字符串的第一个字符进行精确匹配,然后在其中进行模糊匹配。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-21
    • 2018-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-23
    • 2018-01-03
    相关资源
    最近更新 更多