【问题标题】:Search for duplicates by word match按单词匹配搜索重复项
【发布时间】:2021-07-11 14:39:58
【问题描述】:

我的列表中有这样的数据:

Microsoft Ltd
Microsoft
Google Inc
Amazon Ltd.
Amazon Ltd.
DropBox Corporation Ltd.
DropBox Corporation

我当前的解决方案能够检测到完全匹配的重复项。因此,它当前会输出:

Amazon Ltd.
Amazon Ltd.

我想添加一些可能性,以便这些也可以在输出列表中:

Microsoft Ltd
Microsoft
Amazon Ltd.
Amazon Ltd.
DropBox Corporation Ltd.
DropBox Corporation

这是我当前的代码:

var dups = companyList.AsEnumerable()
.Where(g => !string.IsNullOrWhiteSpace(g.Name))
.GroupBy(dr => dr.Name.Trim())
.Where(gr => gr.Count() > 1)
.SelectMany(g => g)
.OrderBy(c => c.Name)
.ToList();

我会非常感谢任何善意的建议,这将导致实现这种检查的解决方案?我个人认为这里没有任何可能的逻辑解决方案?也许只是某种基于分数的Levenshtein Distance 计算和检测?如果无论如何都不可能,至少获得这些是有益的(通过多个单词匹配,例如两个):

DropBox Corporation Ltd.
DropBox Corporation

【问题讨论】:

  • @TimSchmelter 理想情况下,订单无关紧要。因此,它也将涵盖订单混乱的情况。所以DropBox Corporation Ltd.Corporation DropBox 也会被检测到。
  • 是否也应该匹配“Google”?
  • @AlexanderPetrov 为简单起见,Google 案例可以简化。我已经编辑了我的问题

标签: c# .net linq


【解决方案1】:

您可以编写自己的相等比较器,在其中定义两个公司名称何时被视为同一公司。它需要实现两个方法:

  • GetHashCode() 哪种类型的公司将被比较 - 它们需要具有相同的哈希码值。在您的情况下,我没有看到比为所有人硬编码一个值以便相互比较更好的选择。
  • Equals() 表示如果两家公司实际上被认为是同一家,通过检查名称。你可以随心所欲地调整它,你会发现它正在你的测试集上工作(我想一些实验将是必要的)。

您可以在下面找到我的实现,当我假设公司最多相差一个字时被视为相同。

public class Program
{
    public static void Main()
    {
        var companyNames = new[]
        {
            "Microsoft Ltd",
            "Microsoft",
            "Google Inc",
            "Google Drive Inc",
            "Amazon Ltd.",
            "Amazon Ltd.",
            "DropBox Corporation Ltd.",
            "DropBox Corporation",
            "Corporation DropBox"
        };

        var companies = companyNames.Select(cn => new Company {Name = cn});

        var groups = companies
            .GroupBy(c => c, new CompanyComparer())
            .Where(gr => gr.Count() > 1);

        PrintResults(groups);

        Console.ReadKey();
    }



    private static void PrintResults(IEnumerable<IGrouping<Company, Company>> groups)
    {
        foreach (var grp in groups)
        {
            foreach (var c in grp)
            {
                Console.WriteLine(c.Name);
            }
            Console.WriteLine();
        }
    }
}

public class Company
{
    public string Name { get; set; }
}

public class CompanyComparer : IEqualityComparer<Company>
{
    public bool Equals(Company x, Company y)
    {
        if (x?.Name == null || y?.Name == null) return false;

        var xWords = GetWordsSet(x.Name);
        var yWords = GetWordsSet(y.Name);

        // make company with more words first
        if (xWords.Count < yWords.Count)
        {
            var temp = xWords;
            xWords = yWords;
            yWords = temp;
        }

        var commonWords = xWords.Count(xWord => yWords.Contains(xWord));

        return xWords.Count - commonWords <= 1;
    }

    public int GetHashCode(Company obj) => 0; // only companies with same hash code will be compared

    private static ISet<string> GetWordsSet(string name) =>
        name.Split().Select(n => n.ToLower()).ToHashSet();
}

它给出了输出:

Microsoft Ltd
Microsoft

Google Inc
Google Drive Inc

Amazon Ltd.
Amazon Ltd.

DropBox Corporation Ltd.
DropBox Corporation
Corporation DropBox

【讨论】:

  • 哇,这看起来很高级!我去看看!
【解决方案2】:

您可以通过删除标点符号和诸如“Inc”、“Corp”之类的词(参见下面的部分示例)以及删除括号来进行一定程度的“规范化”,但最终这是一个非常困难的问题,因为 (i)缩写; (ii) 位置说明符(东、北……); (iii) 公司分类法:是子公司、分公司、特许经营商还是独立公司?

最终,同义词列表可能是最好的方法,加上一些轻微的规范化以删除常见的公司实体类型指示符。

    private static string Clean(string corporation)
    {
        corporation = corporation.EndsWith("Inc") ? corporation.Substring(0, corporation.Length - 3) : corporation;
        return corporation
            .Replace(" LLC", "")
            .Replace(" S.A.", "")
            .Replace(" SA", "")
            .Replace(" S.L.", "")
            .Replace(" SL", "")
            .Replace("(1)", "")
            .Replace(" GmbH", "")
            .Replace("(UK) Ltd.", "")
            .Replace(" Limited", "")
            .Replace(" Corporation", "")
            .Replace(" Corp.", "")
            .Replace(" Corp ", " ")
            .Replace(" Ltd.", "")
            .Replace(" Ltd", "")
            .Replace(" Inc.", "")
            .Replace("(Pa)", "")
            .Replace(" Inc ", " ")
            .Replace(" Corporation", "")
            .Replace(", LLP.", "")
            .Replace(" N.V.", "").Trim();
    }

【讨论】:

  • 这就是为什么会有这样的网站。这是一个好主意,可以先消除可能的缩写,然后再进行比较。这也可能是解决这个问题的最简单的方法。其他选项可能基于某种带有评分的算法。算法会生成一个分数,然后根据这个分数执行重复检测。如果没有更高级的解决方案,我会选择这个。
  • @mrwd 是的,这个特定问题的评分或单词相似性问题在于,有许多非常相似的公司名称只有一个元音不同。
猜你喜欢
  • 1970-01-01
  • 2014-08-17
  • 2011-05-23
  • 1970-01-01
  • 1970-01-01
  • 2020-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-17
相关资源
最近更新 更多