通过模糊匹配多个变量来匹配实体

时间:2018-08-10 10:14:57

标签: python string pandas matching

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

假设我有一个熊猫数据框,其中包含变量“公司名称”,“股票代码”和“国家/地区”。简化的子集可能看起来像这样:

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"]])

Subset of dataset

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

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

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

但是,所有三列都需要通过模糊逻辑进行比较:公司,股票代码和国家/地区可能用不同的方式书写。例如。 “ Vestas风力系统”与“ Vestas”或“美国”与“美国”。

另一个复杂性是,“股票交易代码”和“国家/地区”列均可能包含NaN值(公司名称绝不能为空)。

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


我当前的计划:

我想通过利用三列信息来匹配公司。跨列的实体越相似,匹配的可能性就越高。此外,每列的权重应该不同:仅仅因为两家公司都位于美国,并不意味着它们是同一家公司。因此,例如,“国家/地区”列的权重应该较低。

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

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],
                     ["...", "...", "..."]])

Company name matching

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]])

Ticker matching

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]])

Country matching

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

所以现在我在不同的列上都有相似度分数。然后,我想使用这些相似性来识别初始数据框的哪些行代表相同的公司。如前所述,我想对列相似性应用不同的权重:假设我要使用以下权重:

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

2 个答案:

答案 0 :(得分:1)

我将通过以下方式进行处理:

  1. 确保“国家/地区”列清洁。进行一些探索以发现诸如“美国”,“美国”,“俄罗斯”和“俄罗斯联邦”等案件。确保每个国家的拼写方式都一致。

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

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

答案 1 :(得分:0)

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

有几种可用的选项,我发现最好(和最便宜)的一种是使用Dedupe。您可以通过网站使用该应用程序进行“聚类”(我认为这是付费的,但需要大量免费试用),也可以通过pip进行安装(这种方式比较棘手,但是如果您将投入生产)。

聚类的工作原理是训练模型,并通过简单的手动过程反复回答“是否满足”,直到您有足够的示例供模型推断出哪个字符串与每个字符串相等其他。然后它将通过模型运行数据集,分配cluster_id将所有匹配的字符串分组在一起,然后您可以检查结果。