【问题标题】:Find matching entries in list which are different在列表中查找不同的匹配条目
【发布时间】:2017-08-22 04:44:09
【问题描述】:

我有两个列表。第一个包含像

这样的条目
  • RB 莱比锡 vs SV 达姆施塔特 98
  • 柏林赫塔 vs 霍芬海姆
  • ..

在第二个中包含基本相同的条目,但可以以不同的形式编写。例如:

  • 柏林赫塔 vs TSG 霍芬海姆
  • RB 莱比锡 vs 达姆施塔特 98
  • ..

等等。两个列表代表相同的体育比赛,但它们可以使用备用团队名称并且出现的顺序不同

我的目标(呵呵双关语)是将两个列表统一为一个并匹配相同的条目并丢弃未出现在两个列表中的条目。

我已经尝试过使用Levensthein distance 和模糊搜索。 我想过使用机器学习,但不知道如何开始。

希望有任何帮助和想法!

【问题讨论】:

  • 有助于查看列表、样本数据和所需输出的属性
  • 如果您消除了所有全大写子字符串(例如 TSG、SV、RB 和 BSC),那么这两个列表的名称匹配程度如何?
  • 它们可能已经是相同的,这将非常好或仍然存在很大差异,例如 M'gladbachMonchengladbach 是同一个团队,但写法不同。
  • 每个列表中使用的名称是否一致,例如如果列表使用一次M'gladbach,那么它是否总是使用M'gladbach
  • 是的,一个列表的名字是一致的。

标签: c# algorithm sorting comparison fuzzy-search


【解决方案1】:

您可以使用 Linear Programming 结合您已经提到的 Levenshtein 距离来解决此问题。线性规划是一种常用的优化技术,用于解决优化问题,比如这个。检查此链接以了解如何使用 Solver Foundation in C# 的示例。此示例与您遇到的具体问题无关,但它是该库如何工作的一个很好的示例。

提示: 您需要在 2 个列表之间的每对团队/字符串之间建立一个距离矩阵。假设两个列表都有 N 个元素。在矩阵的第 i 行中,您将有 N 个值,第 j 个值将指示第一个列表中的第 i 个元素和第二个列表中的第 j 个元素之间的 Levenshtein 距离。然后,您需要设置约束。约束是:

  1. 每一行的和必须等于1
  2. 每列的和等于 1
  3. 每个系数(矩阵项)必须为 0 或 1

几个月前我已经解决了同样的问题,这种方法对我来说非常有效。

成本函数将是总和:`

sum(coef[i][j] * dist[i][j] for i in [1, n] and for j in [1, n])

`。您希望最小化此函数,因为您希望映射后 2 个集合之间的整体“距离”尽可能小。

【讨论】:

    【解决方案2】:

    您可以使用BK-tree(我搜索了 C# 实现并找到了两个:12)。使用 Levenshtein 距离作为度量。或者,从列表中的名称中删除全部大写的子字符串以改进度量(请注意,这不会意外地给您留下空的名称字符串)。

    1. Put the names from the first list in the BK-tree
    2. Look up the names from the second list in the BK-tree
      a. Assign an integer token to the name pair, stored in a Map<Integer, Tuple<String, String>>
      b. Replace each team name with the token
    3. Sort each token pair (so [8 vs 4] becomes [4 vs 8])
    4. Sort each list by its first token in the token pair, 
       then by the second token in the token pair (so the list
       would look like [[1 vs 2], [1 vs 4], [2 vs 4]])
    

    现在您只需遍历两个列表

    int i1 = 0
    int i2 = 0
    while(i1 < list1.length && i2 < list2.length) {
      if(list1[i1].first == list2[i2].first && list1[i1].second == list2[i2].second) {
        // match
        i1++
        i2++
      } else if(list1[i1].first < list2[i2].first) {
        i1++
      } else if(list1[i1].first > list2[i2].first) {
        i2++
      } else if(list1[i1].second < list2[i2].second {
        i1++
      } else {
        i2++
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-08
      • 1970-01-01
      • 2014-08-04
      • 1970-01-01
      • 2014-01-05
      • 2013-04-10
      相关资源
      最近更新 更多