首页 > 解决方案 > 通过多个变量的模糊匹配来匹配实体

问题描述

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

假设我有一个 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:如何以最有效的方式完成此任务?

标签: pythonstringpandasmatching

解决方案


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

  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。


推荐阅读