【问题标题】:Match entities by fuzzy matching of multiple variables通过多个变量的模糊匹配来匹配实体
【发布时间】:2019-01-17 22:25:40
【问题描述】:

我有一个多维度的模糊字符串匹配问题:

假设我有一个 pandas 数据框,其中包含变量“公司名称”、“股票代码”和“国家/地区”。简化的子集可能如下所示:

pd.DataFrame(columns = ["Company name", "Ticker", "Country"], 
             data = [["Vestas Wind Systems", "VWS.CO", "Denmark"],
                     ["Vestas", "VWS", "Denmark"],
                     ["Vestas Wind", "VWS", np.nan], 
                     ["Amazon.com Inc", np.nan, "United States of America"],
                     ["AMAZONIA", "BAZA3 BZ", "Brazil"],
                     ["AMAZON.COM", "AMZN US", "United States"]])

整个数据框将包含数十万行。

我想要的是识别数据框中的公司,它们是相同的。 在这种情况下,这意味着确定第 0、1、2 行都是公司“Vestas Wind Systems”的不同表达方式,第 3、5 行都代表“Amazon.com Inc”,第 4 行代表“Amazonia”。

为了增加正确匹配的机会,我假设最好利用所有三列的信息。

但是,所有三列都需要通过模糊逻辑进行比较:公司、股票代码和国家/地区都可能以不同的方式书写。例如。 “Vestas Wind Systems”与“Vestas”或“United States of America”与“United States”。

另一个复杂性是 Ticker 和 Country 列都可能包含 NaN 值(公司名称永远不会为空)。

问题 1:解决此问题的理想方法是什么?


我目前的计划:

我想通过利用三列中的信息来匹配公司。列中的实体越相似,匹配的概率就越高。此外,每列应该有不同的权重:仅仅因为两家公司位于美国,并不意味着它们是同一家公司。因此,例如,Country 列的权重应该较低。

我目前尝试在每一列上使用模糊算法来识别相似的字符串表示。这将产生这样的结果,其中分数代表字符串相似度:

pd.DataFrame(columns = ["Company name 1", "Company name 2", "Score"], 
             data = [["vestas wind systems", "vestas wind", 0.9],
                     ["vestas wind", "vestas", 0.85],
                     ["amazon.com inc", "amazon.com", 0.84],
                     ["amazon.com", "amazonia", 0.79],
                     ["vestas wind systems", "vestas", 0.75],
                     ["amazon.com inc", "amazonia", 0.70], 
                     ["vestas", "amazonia", 0.4],
                     ["...", "...", "..."]])

pd.DataFrame(columns = ["Ticker 1", "Ticker 2", "Score"], 
             data = [["vws.co", "vws", 0.8],
                     ["baza3 bz", "amzn us", 0.6],
                     ["vws", "amzn us", 0.4],
                     ["vws.co", "amzn us", 0.35],
                     ["baza3 bz", "vws.co", 0.3],
                     ["baza3 bz", "vws", 0.28]])

pd.DataFrame(columns = ["Country 1", "Country 2", "Score"], 
             data = [["united states", "united states of america", 0.8],
                     ["brazil", "denmark", 0.3],
                     ["brazil", "united states", 0.28],
                     ["brazil", "united states of america", 0.26],
                     ["denmark", "united states", 0.25],
                     ["denmark", "united states of america", 0.23]])

注意:我意识到我应该在模糊匹配之前通过正则表达式进行一些简单的字符串清理,但为了简单起见,我们假设我已经这样做了。同样,我已将上述结果中的所有字符串都转换为小写。

所以现在我在不同的列中有相似度分数。然后,我想使用这些相似性来确定初始数据框中的哪些行代表相同的公司。正如我之前提到的,我想对列相似性应用不同的权重:假设我想使用以下权重:

weights = {"Company name" : 0.45, "Ticker" : 0.45, "Country" : 0.1}

也就是说,当比较数据框中的任意两行时,它们的相似度得分为

similarity_score = 0.45 * Company Name similarity score + 0.45 * Ticker Name similarity score + 0.1 * Country similarity score

例如第0行和第1行的相似度得分为:

similarity_score_0_1 = 0.45 * 0.75 + 0.45 * 0.8 + 0.1 * 1.0 = 0.7975

当某些行的代码和/或国家/地区为空值时,这当然会成为一个问题。

最后 - 当我在数据框中有几十万行时,计算所有行之间的相似度分数变得非常耗时。

问题 2:如何以最有效的方式完成此任务?

【问题讨论】:

  • 只有两个cmets::你可以搜索的主题叫做实体识别。一般来说,没有最佳解决方案,因此无法准确回答两个,因为您必须考虑多种权衡
  • 使用欧式距离进行匹配怎么样?可以匹配 n 个变量。
  • 谢谢@Quickbeam2k1,我不知道该主题有实际名称。我会尝试搜索它。
  • 谢谢,@Waleed。我会调查的!

标签: python string pandas matching


【解决方案1】:

模糊匹配可能不会在这里解决问题,因为它本质上是 Levenshtein 距离搜索,它根据您需要更改的字符数进行匹配,以使第一个字符串等于第二个字符串。这意味着虽然您可以设置阈值以将“USA”与“United States”匹配,但您可以看到这需要大量字符更改才能使第一个等于第二个,因此必须设置阈值非常低。显然这会导致很多其他的比赛质量很差。

有多种选择,我认为最好(也是最便宜)的一种是使用Dedupe。您可以通过网站使用该应用程序进行“集群”(我认为这是付费的,但有大量的免费试用),或者您可以通过 pip 安装它(这种方式非常棘手,但如果您将这投入生产)。

集群的工作原理基本上是训练模型,通过一个简单的手动过程一遍又一遍地回答“这是否匹配”,直到您有足够的示例让模型能够推断出您的哪些字符串等于每个其他。然后它将通过模型运行您的数据集,分配一个 cluster_id 以将所有匹配的字符串分组在一起,然后您可以检查结果。

【讨论】:

    【解决方案2】:

    我会通过以下方式处理它:

    1. 确保“国家/地区”列是干净的。进行一些探索以检测“USA”和“United States”、“Russia”和“Russian Federation”等案例。确保每个国家/地区的拼写方式一致。

    2. 如果您的目标是找到相同的公司,您可以通过仅将记录与来自同一国家/地区的公司进行比较来缩小比较空间(假设您已经完成了 1.)。所以你只会比较例如。丹麦公司对所有丹麦公司。这将节省您的时间。但是,必须将缺少国家的记录与所有记录进行比较。

    3. 研究 TFIDF,一种用于信息检索的简单有效的方法。我从事过一项非常相似的任务,事实证明 TFIDF 比 Levenshtein 距离更好。在这种情况下,TFIDF 的优势在于它会减少常用短语(inc.、co.、company、ltd 等)的权重,而 Fuzzy 会看到 ltd 并认为它是一个很好的匹配项(尽管您可能有 CocaCola Ltd.和百事可乐有限公司)。对于 TFIDF,您可能会考虑在进行比较时连接所有相关列。 我使用了 sklearn 的 TfidfVectorizer。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-25
      • 1970-01-01
      • 2016-02-11
      • 2021-10-17
      相关资源
      最近更新 更多