【问题标题】:Excel: Imperfect Matches [duplicate]Excel:不完美匹配[重复]
【发布时间】:2014-10-22 01:54:18
【问题描述】:

我有两个表格,每个表格都填满了设施名称和邮政编码(以及一堆不相关的其他数据)。这些表格来自两个不同的来源,我想将它们链接起来。问题是,设施名称的写法很多时候略有不同(缩写、撇号等)。邮政编码恰好是一个很好的限制器,将数千个潜在匹配项减少到少数几个。我的问题是,

在给定邮政编码匹配和近似名称匹配的情况下,如何匹配这两个表:

|facility|zip  |         |facility|zip  |
|azyt    |10000| No Match|aaaa    |10000|
|abba    |10000| Match   |abb'    |10000|

我想到的一种方法是针对表 A 中的每一行,梳理表 B 的邮政编码并找到所有具有匹配邮政编码的行。然后以某种方式测试哪个名称最相似,可能通过比较最左边的字符(?)。总有一个匹配,只是不完美。

这是我的不完整代码:

 Dim facilityName, facilityZip, otherName

  For i = 1 To Worksheets("Facility").UsedRange.Rows.Count
    facilityName = Worksheets("Facility").Cells(i, 2)
    facilityZip = Worksheets("Facility").Cells(i, 4)

    'Grab all rows in OTHER that have same ZIP
    For j = 1 To Worksheets("Other").UsedRange.Rows.Count
      otherName = Array()
      ub = UBound(otherName) + 1
      If Worksheets("Other").Cells(j, 3).Value = facilityZip Then
        ReDim Preserve otherName(0 To ub)
        otherName(ub) = j
      End If
    Next j

    'Compare names
     For Each rw In otherName
       'here I would compare each result to the current facilityName. There's likely a better way to do this...
     Next rw

    Next i

有关此代码的帮助、建议甚至不同的方法都会非常有帮助!

谢谢!

【问题讨论】:

  • 您实际上并不需要 otherName 数组 - 您可以直接在扫描“其他”表的内部循环中进行比较。
  • 你可能是对的。我的想法是,由于我正在寻找最接近的匹配,我想首先存储所有可能的匹配,然后找到最接近的匹配。一些匹配将是精确的,而另一些可能是消除过程。此外,我认为可能有一种方法可以通过排除已选择的任何可能的“otherSheet”候选者来优化代码。但这不是必需的。
  • 好点:如果您需要对可能的匹配进行排名,那么您现有的代码是一个好方法。我想你究竟如何对匹配进行排名是一个问题:你可以从一个子字符串匹配开始,也许像检查 Levenshtein 差异之类的东西:stackoverflow.com/questions/21276721/…
  • 嗯,我想知道 levenshtein 方法在这里如何工作。例如,一张纸可能会说“花园草地共价”并与简单的“花园草地”匹配。但是加上整个词可能比“花园购物中心”之类的词更“遥远”。但也许如果我们将字符串的大小限制为更小,嗯。你怎么看?
  • 我不是这方面的专家 - Levenshtein Distance 是我所知道的唯一“正式”方法,但我相信还有很多其他方法。如果您的变化主要发生在字符串的末尾,那么限制大小可能是一个好主意。基本上你需要尝试一些不同的算法,看看什么能给你“最好”的结果。

标签: excel vba


【解决方案1】:

使用来自here 的 Levenshtein 距离方法:

Dim facilityName, facilityZip, hudName, hudZip, provNum, lowerLen, levNum, tmpLev, resultHudNum, resultHudName


For i = 1 To Worksheets("Facility").UsedRange.Rows.Count
  With Worksheets("Facility")
    facilityName = .Cells(i, 2)
    facilityZip = .Cells(i, 3)
  End With
  levNum = 5
  resultHudNum = 0
  For j = 1 To Worksheets("Sheet1").UsedRange.Rows.Count
    With Worksheets("Sheet1")
      hudName = .Cells(j, 2)
      hudZip = .Cells(j, 4)
      hudNum = .Cells(j, 1)
    End With
    If hudZip = facilityZip Then
      If Len(facilityName) < Len(hudName) Then
        lowerLen = Len(facilityName)
      Else
        lowerLen = Len(hudName)
      End If
      tmpLev = Levenshtein(Mid(facilityName, 1, lowerLen), Mid(hudName, 1, lowerLen))
      If tmpLev < levNum Then
          levNum = tmpLev
          resultHudNum = hudNum
          resultHudName = hudName
      End If
    End If
  Next j
  If resultHudNum <> 0 Then
    Worksheets("Facility").Cells(i, 4).Value = resultHudNum
    Worksheets("Facility").Cells(i, 5).Value = resultHudName
  Else
    Worksheets("Facility").Cells(i, 4).Value = "000000"
    Worksheets("Facility").Cells(i, 5).Value = ""
  End If
Next i

可以通过更改 levNum 中的值来修改字符串之间所需的相似度。

感谢@Tim 的帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多